SPOJ Optimal Marks

https://vjudge.net/problem/SPOJ-OPTM

每位分别考虑后,相当于给所有点分两类,不同类之间的边会产生花费。即求最小割,源点向所有已知的这位为0的点连无穷边,所有已知的这位为1的点向汇点连无穷边。为了使总和尽量小,跑完最小割后,从汇点开始dfs找出残留网络种能到达汇点的点,置为1,除它们外的所有点都置为0。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<algorithm>
  5 using namespace std;
  6 #define LL long long
  7 
  8 int n,m,numofmk,T;
  9 #define maxn 511
 10 #define maxm 3011*4+maxn*2
 11 int mk[maxn],ans[maxn];
 12 
 13 struct Edge{int to,next,cap,flow;};
 14 struct Net
 15 {
 16     int n,le,s,t,first[maxn],dis[maxn],cur[maxn],que[maxn],head,tail; Edge edge[maxm]; bool vis[maxn];
 17     void clear(int N) {n=N; le=2; memset(first,0,sizeof(first)); memset(vis,0,sizeof(vis));}
 18     void in(int x,int y,int c) {Edge &e=edge[le]; e.to=y; e.cap=c; e.flow=0; e.next=first[x]; first[x]=le++;}
 19     void insert(int x,int y,int c) {in(x,y,c); in(y,x,0);}
 20     bool bfs()
 21     {
 22         memset(dis,0,sizeof(dis));
 23         head=0; tail=1; que[0]=s; dis[s]=1;
 24         while (head!=tail)
 25         {
 26             int x=que[head++];
 27             for (int i=first[x];i;i=edge[i].next)
 28             {
 29                 Edge &e=edge[i]; if (dis[e.to] || e.cap==e.flow) continue;
 30                 dis[e.to]=dis[x]+1; que[tail++]=e.to;
 31             }
 32         }
 33         return dis[t]>0;
 34     }
 35     int dfs(int x,int a)
 36     {
 37         if (x==t || !a) return a;
 38         int flow=0,f;
 39         for (int &i=cur[x];i;i=edge[i].next)
 40         {
 41             Edge &e=edge[i];
 42             if (dis[e.to]==dis[x]+1 && (f=dfs(e.to,min(a,e.cap-e.flow)))>0)
 43             {
 44                 e.flow+=f;
 45                 flow+=f;
 46                 edge[i^1].flow-=f;
 47                 a-=f;
 48                 if (!a) break;
 49             }
 50         }
 51         return flow;
 52     }
 53     int Dinic(int S,int T)
 54     {
 55         s=S; t=T;
 56         int flow=0;
 57         while (bfs())
 58         {
 59             for (int i=1;i<=n;i++) cur[i]=first[i];
 60             flow+=dfs(s,0x3f3f3f3f);
 61         }
 62         return flow;
 63     }
 64     void dfs2(int x)
 65     {
 66         vis[x]=1;
 67         for (int i=first[x];i;i=edge[i].next)
 68             if (edge[i^1].cap>edge[i^1].flow && !vis[edge[i].to]) dfs2(edge[i].to);
 69     }
 70 }g,g2;
 71 
 72 int main()
 73 {
 74     scanf("%d",&T);
 75     while (T--)
 76     {
 77         scanf("%d%d",&n,&m);
 78         g.clear(n+2);
 79         for (int i=1,x,y;i<=m;i++)
 80         {
 81             scanf("%d%d",&x,&y);
 82             g.insert(x,y,1); g.insert(y,x,1);
 83         }
 84         memset(mk,-1,sizeof(mk));
 85         memset(ans,0,sizeof(ans));
 86         scanf("%d",&numofmk);
 87         for (int i=1,x;i<=numofmk;i++)
 88         {
 89             scanf("%d",&x);
 90             scanf("%d",&mk[x]);
 91             ans[x]=mk[x];
 92         }
 93         
 94         for (int i=0;i<=30;i++)
 95         {
 96             g2=g;
 97             for (int j=1;j<=n;j++) if (mk[j]!=-1)
 98             {
 99                 if ((mk[j]>>i)&1) g2.insert(j,n+2,0x3f3f3f3f);
100                 else g2.insert(n+1,j,0x3f3f3f3f);
101             }
102             g2.Dinic(n+1,n+2);
103             memset(g2.vis,0,sizeof(g2.vis));
104             g2.dfs2(n+2);
105             for (int j=1;j<=n;j++) ans[j]|=(g2.vis[j]<<i);
106         }
107         for (int i=1;i<=n;i++) printf("%d\n",ans[i]);
108     }
109     return 0;
110 }
View Code

 

posted @ 2020-02-05 09:11  Blue233333  阅读(131)  评论(0编辑  收藏  举报