D 勤奋的杨老师(二)(最小割)

显然是最小割的经典应用“二者选一”

这里有一个用其他算法不好解决的地方,选择了v,则必须选择所有的u,而对于这个直接建好v指向u的边,容量设为正无穷即可。(即该边不可被割)

源点指向某个知识点,边容量为收益大小,这个点再指向汇点,边容量为损失大小。

对于每个点,要么选(切断与汇点的联系),要么不选(切断与源点的联系),用链接源点的收益和减去最小割就是答案。

最小割的巨大优势是,它可以同时考虑所有点的选择,而得出最优解。

最小割==最大流

最小割:将原图割成只与源点相连和只与汇点相连的两个集合,需要割掉的最小边权和

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<vector>
  5 #include<algorithm>
  6 #include<queue>
  7 #include<map>
  8 using namespace std;
  9 typedef  long long ll;
 10 const int MAX_N = 1600;  
 11 const int MAX_M = 50000;  
 12 const int INF = 1000000000;  
 13 struct edge {
 14     int v, c, next;   
 15 } e[MAX_M];
 16 int p[MAX_N], eid;
 17 void init() {
 18     memset(p, -1, sizeof(p));
 19     eid = 0;
 20 }
 21 void insert(int u, int v, int c) {  
 22     e[eid].v = v;
 23     e[eid].c = c;
 24     e[eid].next = p[u];
 25     p[u] = eid++;
 26 }
 27 void addedge(int u, int v, int c) {  
 28     insert(u, v, c);
 29     insert(v, u, 0);  
 30 }
 31 int S, T;  
 32 int d[MAX_N];  
 33 bool CountLayer() {  
 34     memset(d, -1, sizeof(d));
 35     queue<int> q;
 36     q.push(S);
 37     d[S] = 0;
 38     while (!q.empty()) {
 39         int u = q.front();
 40         q.pop();
 41         for (int i = p[u]; i != -1; i = e[i].next) {
 42             int v = e[i].v;
 43             if (e[i].c > 0 && d[v] == -1) {
 44                 q.push(v);
 45                 d[v] = d[u] + 1;
 46             }
 47         }
 48     }
 49     return (d[T] != -1);  
 50 }
 51 
 52 ll dfs(int u, int flow) {  
 53     if (u == T) {
 54         return flow;
 55     }
 56     ll res = 0;
 57     for (int i = p[u]; i != -1; i = e[i].next) {
 58         int v = e[i].v;
 59         if (e[i].c > 0 && d[u] + 1 == d[v]) {
 60             ll tmp = dfs(v, min(flow, e[i].c));  
 61             flow -= tmp;
 62             e[i].c -= tmp;
 63             res += tmp;
 64             e[i ^ 1].c += tmp;  
 65             if (flow == 0) {  
 66                 break;
 67             }
 68         }
 69     }
 70     if (res == 0) {  
 71         d[u] = -1;
 72     }
 73     return res;
 74 }
 75 
 76 ll maxflow() {  
 77     ll res = 0;
 78     while (CountLayer()) {
 79         res += dfs(S, INF);  
 80     }
 81     return res;
 82 }
 83 
 84 int main()
 85 {    int n;
 86     cin>>n;
 87     ll x,y,sum=0;
 88     S=0,T=n+1;
 89     init();
 90     for(int i=1;i<=n;i++)
 91     {    
 92         cin>>x>>y;
 93         int res=x-y;
 94         if(res>0) addedge(0, i, res),sum+=res;
 95         
 96         else addedge(i, n+1, -res);
 97         
 98     }
 99     while(~scanf("%d%d",&x,&y))
100     {
101         addedge(y, x, INF);
102     }
103     cout<<sum-maxflow()<<endl;
104     
105     return 0;
106 } 
View Code

猜你喜欢

转载自www.cnblogs.com/lnu161403214/p/9004506.html
d
<d>
d'd