标签:from tps 最小割 open cto view for name ges
看数据范围,加上题中频繁提到的冲突,就可以想到算法是最小割。
1.同意睡觉的,源点就像他连一条容量为1的边。割掉它就代表他背叛了自己的意愿。
2.同理,不同意睡觉的,就像汇点连一条边。
3.考虑每一对朋友。如果两个朋友意见相反,就互相连一条容量为1的边,割掉其中的任意一条就代表朋友之间发生了冲突,代价为1.而且根据网络流性质,一定不会同时割掉这两条边。
4.如果一对朋友之间意见相同呢?其实还是建边还是和上面一样。因为如果割掉这条边的原因一定是其中一个人为了照顾和自己意见相反的其他朋友,而和这个朋友发生了冲突。
画一个图:
1,2同意睡觉,且是朋友;3,4不同意睡觉;并且1和3,1和4还是朋友。
最小割为2,可以有这么几个典型情况:
1.割掉边(6), (7):3和4为了照顾1,变卦了。
2.割掉边(4), (5):1分别和3, 4发生冲突。
3.割掉边(1), (3):1为了照顾3和4,变卦了,因此与2发生了冲突。
放代码啦:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(‘ ‘) 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 305; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), last = ‘ ‘; 25 while(!isdigit(ch)) {last = ch; ch = getchar();} 26 while(isdigit(ch)) {ans = ans * 10 + ch - ‘0‘; ch = getchar();} 27 if(last == ‘-‘) ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) x = -x, putchar(‘-‘); 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + ‘0‘); 35 } 36 37 int n, m, t; 38 39 struct Edge 40 { 41 int from, to, cap, flow; 42 }; 43 vector<Edge> edges; 44 vector<int> G[maxn]; 45 void addEdge(int from, int to) 46 { 47 edges.push_back((Edge){from, to, 1, 0}); 48 edges.push_back((Edge){to, from, 0, 0}); 49 int sz = edges.size(); 50 G[from].push_back(sz - 2); 51 G[to].push_back(sz - 1); 52 } 53 54 int dis[maxn]; 55 bool bfs() 56 { 57 Mem(dis, 0); dis[0] = 1; 58 queue<int> q; q.push(0); 59 while(!q.empty()) 60 { 61 int now = q.front(); q.pop(); 62 for(int i = 0; i < (int)G[now].size(); ++i) 63 { 64 Edge& e = edges[G[now][i]]; 65 if(!dis[e.to] && e.cap > e.flow) 66 { 67 dis[e.to] = dis[now] + 1; 68 q.push(e.to); 69 } 70 } 71 } 72 // for(int i = 1; i <= n; ++i) printf("%d ", dis[t]); enter; 73 return dis[t]; 74 } 75 int cur[maxn]; 76 int dfs(int now, int res) 77 { 78 if(now == t || res == 0) return res; 79 int flow = 0, f; 80 for(int& i = cur[now]; i < (int)G[now].size(); ++i) 81 { 82 Edge& e = edges[G[now][i]]; 83 if(dis[e.to] == dis[now] + 1 && (f = dfs(e.to, min(res, e.cap - e.flow))) > 0) 84 { 85 e.flow += f; 86 edges[G[now][i] ^ 1].flow -= f; 87 flow += f; res -= f; 88 if(res == 0) break; 89 } 90 } 91 return flow; 92 } 93 94 int minCut() 95 { 96 int flow = 0; 97 while(bfs()) 98 { 99 Mem(cur, 0); 100 flow += dfs(0, INF); 101 } 102 return flow; 103 } 104 105 int main() 106 { 107 n = read(); m = read(); 108 t = n + 1; 109 for(int i = 1; i <= n; ++i) 110 { 111 int x = read(); 112 if(x) addEdge(0, i); 113 else addEdge(i, t); 114 } 115 for(int i = 1; i <= m; ++i) 116 { 117 int x = read(), y = read(); 118 addEdge(x, y); addEdge(y, x); 119 } 120 write(minCut()); enter; 121 return 0; 122 }
标签:from tps 最小割 open cto view for name ges
原文地址:https://www.cnblogs.com/mrclr/p/9696426.html