【Foreign】猜测 [费用流]

猜测

Time Limit: 10 Sec  Memory Limit: 256 MB

Description

  

Input

  

Output

  

Sample Input

  3
  1 1
  1 2
  2 1

Sample Output

  3
  explain:
  (1,1),(1,1),(2,2)不是一个合法猜测(有相同的格子),因此不管怎么猜总是能全部猜中。

HINT

  

Main idea

  给定了若干个标准点,用这些点的横纵坐标分为x集和y集,定义猜点表示从x集和y集中各选一个,不能猜出重复的点,问在所有合法方案中最少包含上述几个标准点。

Solution

  我们看到了这道题目,考虑从费用流的方法下手。

  我们从S->x集:容量为数字出现次数,费用为0y集->T:容量为数字出现次数,费用为0x集->y集:容量为1,若组合成了标准点则费用为1,否则为0

  然后我们这样连边,又由于题目要的是最少包含几个点,那么显然最小费用最大流就是答案了。

Code

  1 #include<iostream>  
  2 #include<algorithm>  
  3 #include<cstdio>  
  4 #include<cstring>  
  5 #include<cstdlib>  
  6 #include<cmath>  
  7 using namespace std;
  8 
  9 const int ONE = 2000001;
 10 const int INF = 2147483640;
 11 
 12 int n,x,y;
 13 int S,T;
 14 int E[1001][1001];
 15 int next[ONE],first[ONE],go[ONE],pas[ONE],Fro[ONE],tot=1;
 16 int from[ONE],q[1000001],dist[200001];
 17 bool vis[ONE];
 18 int tou,wei;
 19 int Ans,w[ONE];
 20 int li[ONE],li_num;
 21 
 22 struct power
 23 {
 24         int x,y;
 25 }a[ONE],time[ONE],Max;
 26 
 27 int get() 
 28 { 
 29         int res,Q=1;    char c;
 30         while( (c=getchar())<48 || c>57)
 31         if(c=='-')Q=-1;
 32         if(Q) res=c-48; 
 33         while((c=getchar())>=48 && c<=57) 
 34         res=res*10+c-48; 
 35         return res*Q; 
 36 }
 37 
 38 void Add(int u,int v,int liu,int z)
 39 {
 40         next[++tot]=first[u];   first[u]=tot;   go[tot]=v;  w[tot]=z;   pas[tot]=liu;   Fro[tot]=u;
 41         next[++tot]=first[v];   first[v]=tot;   go[tot]=u;  w[tot]=-z;  pas[tot]=0;     Fro[tot]=v;
 42 } 
 43 
 44 int Bfs()
 45 {
 46         memset(dist,63,sizeof(dist));
 47         dist[S]=0;  q[1]=S; vis[S]=1;
 48         tou=0;  wei=1;
 49         while(tou<wei)
 50         {
 51             int u=q[++tou];
 52             for(int e=first[u];e;e=next[e])
 53             {
 54                 int v=go[e];
 55                 if(dist[v]>dist[u]+w[e] && pas[e])
 56                 {
 57                     dist[v]=dist[u]+w[e]; from[v]=e;
 58                     if(!vis[v])
 59                     {
 60                         q[++wei]=v;
 61                         vis[v]=1;
 62                     }
 63                 }
 64             }
 65             vis[u]=0;
 66         }
 67         return dist[T]!=dist[T+10];
 68 }
 69 
 70 void Deal()
 71 {
 72         int x=INF;
 73         for(int e=from[T];e;e=from[Fro[e]]) x=min(x,pas[e]);
 74         for(int e=from[T];e;e=from[Fro[e]])
 75         {
 76             pas[e]-=x;
 77             pas[e^1]+=x;
 78             Ans += w[e]*x;
 79         }
 80 }
 81 
 82 int main()
 83 {
 84         n=get();
 85         for(int i=1;i<=n;i++)
 86         {
 87             a[i].x=get();    a[i].y=get();
 88             li[++li_num]=a[i].x; li[++li_num]=a[i].y;
 89         }
 90         
 91         sort(li+1,li+li_num+1);
 92         li_num = unique(li+1,li+li_num+1) - li - 1;
 93         S=0;    T=2*li_num+1;
 94         
 95         for(int i=1;i<=n;i++)
 96         {
 97             a[i].x = lower_bound(li+1,li+li_num+1, a[i].x) - li;
 98             a[i].y = lower_bound(li+1,li+li_num+1, a[i].y) - li;
 99             E[ a[i].x ][ a[i].y ] = 1;
100             time[a[i].x].x++;            time[a[i].y].y++;
101             Max.x = max(Max.x, a[i].x);    Max.y = max(Max.y, a[i].y);
102         }
103         
104         for(int i=1;i<=Max.x;i++) if(time[i].x) Add(S,i,time[i].x,0);
105         for(int i=1;i<=Max.y;i++) if(time[i].y) Add(i+Max.x,T,time[i].y,0);
106         
107         for(int i=1;i<=Max.x;i++)
108         if(time[i].x)
109         for(int j=1;j<=Max.y;j++)
110         if(time[j].y)
111         {
112             if(E[i][j]) Add(i,j+Max.x,1,1);
113             else Add(i,j+Max.x,1,0);
114         }
115         
116         while(Bfs()) Deal();
117         
118         printf("%d",Ans);
119         
120 }
View Code

 

posted @ 2017-03-04 16:22  BearChild  阅读(216)  评论(0编辑  收藏  举报