思路:
以理发的次数当容量,源点到每个人建一条容量为2的边,人到他可达的每个时间点建一条边,每个时间点到汇点建一条容量为m的边。然后判断最大流是否等于2*n。
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #include <string> 8 #include <queue> 9 #include <stack> 10 #include <vector> 11 #include <map> 12 #include <set> 13 #include <functional> 14 #include <time.h> 15 16 using namespace std; 17 18 19 using namespace std; 20 21 const int INF = 1<<30; 22 const int MAXN = 3000; 23 const int MAXE = (int)5e5+10; 24 25 struct Dinic{ 26 struct Edge { 27 int from, to, cap, flow; 28 //从from到to的容量为cap,流量为flow的弧 29 }; 30 31 int n, m, s, t; //结点数,边数(包括反向弧),源点,汇点 32 vector<Edge> edges; //边表。 edges[e]和edges[e^1]互为反向弧 33 vector<int> G[MAXN]; //邻接表,G[i][j]表示结点i的第j条边在e数组中的序号 34 bool vis[MAXN]; //bfs使用 35 int d[MAXN]; //从起点到i的距离 36 int cur[MAXN]; //当前弧下标 37 38 inline void init() { 39 edges.clear(); 40 for (int i = 0; i <= n; i++) { 41 G[i].clear(); 42 } 43 } 44 45 inline void addEdge(int from, int to, int cap) { 46 edges.push_back((Edge){from, to, cap, 0}); 47 edges.push_back((Edge){to, from, 0, 0}); 48 m = edges.size(); 49 G[from].push_back(m-2); 50 G[to].push_back(m-1); 51 } 52 53 bool bfs() { 54 memset(vis, false, sizeof(vis)); 55 queue<int> q; 56 q.push(s); 57 d[s] = 0; 58 vis[s] = true; 59 60 while (!q.empty()) { 61 int u = q.front(); q.pop(); 62 for (int i = 0; i < G[u].size(); i++) { 63 Edge &e = edges[G[u][i]]; 64 if (!vis[e.to] && (e.cap > e.flow)) { //只考虑残量网络中的弧 65 vis[e.to] = true; 66 d[e.to] = d[u]+1; 67 q.push(e.to); 68 } 69 } 70 } 71 return vis[t]; 72 } 73 74 int dfs(int u, int c) { 75 if (u==t || 0==c) return c; 76 int flow = 0, f; 77 for (int &i = cur[u]; i < G[u].size(); i++) { //从上次考虑的弧 78 Edge &e = edges[G[u][i]]; 79 if ((d[u]+1)==d[e.to] && (f = dfs(e.to, min(c, e.cap-e.flow))) > 0) { 80 e.flow += f; 81 edges[G[u][i]^1].flow -= f; 82 flow += f; 83 c -= f; 84 if (0==c) break; 85 } 86 } 87 return flow; 88 } 89 90 int MaxFlow(int s, int t) { 91 this->s = s; this->t = t; 92 int flow = 0; 93 while (bfs()) { 94 memset(cur, 0, sizeof(cur)); 95 flow += dfs(s, INF); 96 } 97 return flow; 98 } 99 void print(int st, int ed) { 100 for (int i = st; i < ed; i++) { 101 bool flag = false; 102 for (int j = 0; j < G[i].size(); j++) { 103 Edge &e = edges[G[i][j]]; 104 if (e.flow==1) { 105 if (flag) printf(" "); 106 printf("%d", e.to); 107 if (flag) { 108 puts(""); 109 break; 110 } 111 flag = true; 112 } 113 } 114 } 115 } 116 }; 117 118 Dinic a; 119 int n, m; 120 121 void solve() { 122 // 时间点: 0~2000 123 // 人: 2001~2000+n 124 //s: 0, t: 2001+n 125 int s = 2001+n; 126 int t = s+1; 127 a.n = t; 128 a.init(); 129 int x, y; 130 int Max = 0; 131 for (int i = 0; i < n; i++) 132 a.addEdge(s, 2001+i, 2); 133 134 for (int i = 0; i < n; i++) { 135 scanf("%d%d", &x, &y); 136 Max = max(Max, x+y); 137 for (int j = 0; j < y; j++) { 138 a.addEdge(2001+i, x+j, 1); 139 } 140 } 141 for (int i = 0; i <= Max; i++) 142 a.addEdge(i, t, m); 143 int ans = a.MaxFlow(s, t); 144 if (2*n==ans) { 145 puts("Yes"); 146 a.print(2001, 2001+n); 147 } else 148 puts("No"); 149 } 150 151 int main() { 152 #ifdef Phantom01 153 freopen("A.txt", "r", stdin); 154 #endif // Phantom01 155 156 while (scanf("%d%d", &n, &m)!=EOF) { 157 solve(); 158 } 159 160 return 0; 161 }
其实做这个题,是为了检验更学的新模板 Dinic