CSUOJ 1319 CX‘s dreams

一看到这个题就知道是最大闭合子图了,关于最大闭合子图的定义和建图,都是看胡伯涛的论文上的。这里有两问,首先是要求闭合图权最大,第二问,也是比较有难度的就是在闭合图权最大的条件下,尽量多的让dream所代表的点出现在最大权闭合图的闭合图中。最大闭合图是最小割模型的一个应用。由于一个流网络的最小割可能不唯一,所以最大闭合图也不一定是唯一的,所以第二问的难度就增加了。

这里的解决方法是借助偏移量来维护两个量,一个是最大流,一个是用到的点数。由题意可得,图中点数最多将达到2002,那么现在选择一个MOD=3000的偏移量。首先要统计图中所有点权为正的点的权和sum。建图的时候,对于每个价值为value的dream,从源点S到dream点连一条流量cap=MOD*value+1的边。这里的+1就表示我选了这个点了,如果这条边在最小割中的话,这个+1就一定会在最后体现出来。对于每个价值为value的付出(用点i表示),若value>=0,加边(S,i,value*MOD);value<0,加边(i,T,-value*MOD)。对原图中所有的有向边,加边(i,j,INF)。跑最大流,得到maxflow。那么根据最大闭合子图的解法,最大闭合子图权=sum-maxflow/MOD,可以完成的梦想=总梦想数n-maxflow%MOD;

命题人ZZY的灵感来自于POJ2987,也是一道最大闭合子图的题目。他的题解在这里:http://blog.csdn.net/kk303/article/details/11843169

至于他的那个建图为什么是对的,或者说可以过,他和我都晕了。

  1 #include <iostream> 
  2 #include <cstdio> 
  3 #include <cstring> 
  4 #include <algorithm> 
  5 using namespace std; 
  6 typedef long long LL; 
  7 #define INF ((LL)2000000007)*((LL)2000000007) 
  8 #define maxn 2010 
  9 #define maxm 200000 
 10 #define MOD 3000 
 11 int u[maxm],v[maxm],next[maxm]; 
 12 LL w[maxm]; 
 13 int first[maxn],d[maxn],work[maxn],q[maxn]; 
 14 int e,S,T; 
 15 int n,m; 
 16   
 17 void init(){ 
 18     memset(first,-1,sizeof(first)); 
 19     e = 0; 
 20 } 
 21   
 22 void add_edge(int a,int b,LL c){ 
 23     //printf("add:from %d to %d,cap = %lld\n",a,b,c); 
 24     u[e] = a;v[e] = b;next[e] = first[a];w[e] = c;first[a] = e++; 
 25     u[e] = b;v[e] = a;next[e] = first[b];w[e] = 0;first[b] = e++; 
 26 } 
 27   
 28 int bfs(){ 
 29     int rear = 0; 
 30     memset(d,-1,sizeof(d)); 
 31     d[S] = 0;q[rear++] = S; 
 32     for(int i = 0;i < rear;i++){ 
 33         for(int j = first[q[i]];j != -1;j = next[j]) 
 34             if(w[j] && d[v[j]] == -1){ 
 35                 d[v[j]] = d[q[i]] + 1; 
 36                 q[rear++] = v[j]; 
 37                 if(v[j] == T)   return 1; 
 38             } 
 39     } 
 40     return 0; 
 41 } 
 42   
 43 LL dfs(int cur,LL a){ 
 44     if(cur == T)    return a; 
 45     for(int &i = work[cur];i != -1;i = next[i]) 
 46         if(w[i] && d[v[i]] == d[cur] + 1) 
 47             if(LL t = dfs(v[i],min(a,w[i]))){ 
 48                 w[i] -= t;w[i^1] += t; 
 49                 return t; 
 50             } 
 51     return 0; 
 52 } 
 53   
 54 LL dinic(){ 
 55     LL ans = 0; 
 56     while(bfs()){ 
 57         memcpy(work,first,sizeof(first)); 
 58         while(LL t = dfs(S,INF))   ans += t; 
 59     } 
 60     return ans; 
 61 } 
 62   
 63 int main() 
 64 { 
 65     while(scanf("%d%d",&n,&m) != EOF){ 
 66         init(); 
 67         S = 0,T = n+m+1; 
 68         int sum = 0; 
 69         for(int i = 1;i <= n;i++){ 
 70             int value; 
 71             scanf("%d",&value); 
 72             add_edge(S,i,value*MOD + 1); 
 73             sum += value; 
 74         } 
 75         for(int i = 1;i <= m;i++){ 
 76             int value; 
 77             scanf("%d",&value); 
 78             if(value >= 0)  add_edge(S,i+n,value*MOD),sum += value; 
 79             else            add_edge(i+n,T,-value*MOD); 
 80         } 
 81         for(int i = 1;i <= n;i++){ 
 82             int t; 
 83             scanf("%d",&t); 
 84             while(t--){ 
 85                 int tmp; 
 86                 scanf("%d",&tmp); 
 87                 add_edge(i,n + tmp,INF); 
 88             } 
 89         } 
 90         LL maxflow = dinic(); 
 91         //printf("maxflow = %lld\n",maxflow); 
 92         printf("%lld %lld\n",sum - maxflow/MOD,n - maxflow%MOD); 
 93     } 
 94     return 0; 
 95 } 
 96   
 97 /************************************************************** 
 98     Problem: 1319 
 99     User: 1234 
100     Language: C++ 
101     Result: Accepted 
102     Time:164 ms 
103     Memory:5420 kb 
104 ****************************************************************/
View Code

 

posted @ 2013-10-02 19:50  浙西贫农  阅读(252)  评论(0编辑  收藏  举报