【LYOI 212】「雅礼集训 2017 Day8」价(二分匹配+最大权闭合子图)

「雅礼集训 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 }
View Code

2017-04-09 21:36:14

原文地址:https://www.cnblogs.com/Konjakmoyu/p/6686548.html