「雅礼集训 2017 Day8」价
内存限制: 512 MiB时间限制: 1000 ms输入文件: z.in输出文件: z.out
【分析】
蛤?一开始看错题了,但是也没有改,因为不会做。
一开始以为是并集全等,其实只是集合内元素个数相等。
如果是一开始的题意的话,就是选了什么药材就要选什么药,明显的一个最大权闭合子图【于是我真的就这样打了,加上暴力还搞了很多分
数量一样的话,男神有一个方法就是放大点权,普通选法的话左边比右边少,所以药的点权+INF,药材的点权-INF,然后做最大权闭合子图【我对此只能膜膜膜
然后题目有一个条件就是要完美匹配。
正解是先做一遍完美匹配,然后药材选了,他的匹配点的药也要选。
证明:
1、可行解一定是这样的。
假设有一个可行解,左右大小都是i,因为左边选的,它的连边的右边一定选,所以i条匹配边一定在集合里面。所以药材的点的匹配边一定在集合里面。
2、这样做出来的答案一定左右大小相等
若左边大于右边,左边一定有一个点的匹配边在集合外,与左边的点的连边的点都选矛盾。
若左边小于右边,右边一定有一个点选了,但是没有选它的匹配点,与你的做法矛盾。
就是这样证明吧?
其实虽然我不会推出结论,但是这题的key的位置实在太明显了,脑洞再大一点就好了。毕竟这种题是证明还好,但是比较难以直接想到结论的。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 #define Maxn 310 9 #define INF 0xfffffff 10 // #define LL long long 11 12 int mymin(int x,int y) {return x<y?x:y;} 13 int n; 14 15 struct node 16 { 17 int x,y,next,f,o; 18 }t[Maxn*Maxn*2]; 19 int first[Maxn],len; 20 21 void ins(int x,int y,int f) 22 { 23 if(x==y) return; 24 t[++len].x=x;t[len].y=y;t[len].f=f; 25 t[len].next=first[x];first[x]=len;t[len].o=len+1; 26 t[++len].x=y;t[len].y=x;t[len].f=0; 27 t[len].next=first[y];first[y]=len;t[len].o=len-1; 28 } 29 30 queue<int > q; 31 int dis[Maxn],st,ed; 32 bool bfs() 33 { 34 while(!q.empty()) q.pop(); 35 memset(dis,-1,sizeof(dis)); 36 q.push(st);dis[st]=0; 37 while(!q.empty()) 38 { 39 int x=q.front(); 40 for(int i=first[x];i;i=t[i].next) if(t[i].f>0) 41 { 42 int y=t[i].y; 43 if(dis[y]==-1) 44 { 45 dis[y]=dis[x]+1; 46 q.push(y); 47 } 48 } 49 q.pop(); 50 } 51 return dis[ed]!=-1; 52 } 53 54 int ffind(int x,int flow) 55 { 56 if(x==ed) return flow; 57 int now=0; 58 for(int i=first[x];i;i=t[i].next) if(t[i].f>0) 59 { 60 int y=t[i].y; 61 if(dis[y]==dis[x]+1) 62 { 63 int a=ffind(y,mymin(flow-now,t[i].f)); 64 t[i].f-=a; 65 t[t[i].o].f+=a; 66 now+=a; 67 } 68 if(now==flow) break; 69 } 70 if(now==0) dis[x]=-1; 71 return now; 72 } 73 74 int ans=0; 75 void max_flow() 76 { 77 while(bfs()) 78 { 79 ans-=ffind(st,INF); 80 } 81 } 82 83 void output() 84 { 85 for(int i=1;i<=len;i+=2) 86 { 87 printf("%d -> %d %d ",t[i].x,t[i].y,t[i].f); 88 } 89 } 90 91 92 //------------------------- 93 int match[Maxn],chw[Maxn],g[Maxn][Maxn]; 94 bool ffind2(int x,int nt) 95 { 96 for(int i=1;i<=g[x][0];i++) 97 { 98 int y=g[x][i]; 99 if(chw[y]!=nt) 100 { 101 chw[y]=nt; 102 if(!match[y]||ffind2(match[y],nt)) 103 { 104 match[y]=x; 105 return 1; 106 } 107 } 108 } 109 return 0; 110 } 111 112 void get_match() 113 { 114 memset(chw,0,sizeof(chw)); 115 memset(match,0,sizeof(match)); 116 int nt=0; 117 for(int i=1;i<=n;i++) 118 { 119 ffind2(i,++nt); 120 } 121 } 122 123 //------------------------- 124 125 126 int main() 127 { 128 scanf("%d",&n); 129 st=n+1;ed=st+1; 130 bool ok=1;int sm=0; 131 for(int i=1;i<=n;i++) 132 { 133 int x; 134 scanf("%d",&x); 135 g[i][0]=x; 136 for(int j=1;j<=x;j++) 137 { 138 int y; 139 scanf("%d",&y); 140 g[i][j]=y; 141 // ins(i,y,INF); 142 } 143 } 144 get_match(); 145 // for(int i=1;i<=n;i++) printf("%d ",match[i]);printf(" "); 146 for(int i=1;i<=n;i++) 147 for(int j=1;j<=g[i][0];j++) 148 { 149 ins(i,match[g[i][j]],INF); 150 } 151 for(int i=1;i<=n;i++) 152 { 153 int w; 154 scanf("%d",&w); 155 w=-w; 156 if(w>0) {ans+=w;ins(st,i,w);} 157 else ins(i,ed,-w); 158 } 159 // output(); 160 max_flow(); 161 printf("%d ",-ans); 162 return 0; 163 }
2017-04-09 21:36:14