题意:现一个队有N个人,每个人已经赢了ai场,还有bi场比赛没打(可能不是跟本队的打,且比赛没有平局)。现给出N*N的矩阵g,g[i][j]表示i和j还有几场比赛要打(g[i][i]=0且g[i][j]=g[j][i])。问第一个人是否可能是整个队赢的最多的。
分析:要第一个人赢的场数最多,那么第一个人剩下的场全部赢(也就确定了其它人最多赢的场数了),而其它人跟队外的人打的话一定要输。而对于g[i][j]来说,这么多场次肯定要人赢和输,我们考虑赢的情况。S连除第一个人,权值为第一个人赢的场数-已赢的场数,对于g[i][j]来说,i,j分别连场次,权值为g[i][j];场次连T,权值为g[i][j]。求最大流,判断是否为总的场次。如果是,那么就可能,输出YES。
#include<stdio.h> #include<iostream> using namespace std; const int maxn=440; const int maxm=21000; const int maxint=0x3fffffff; struct edge { int u,v,w,next; }e[maxm]; int S,T,n,a[maxn],b[maxn],pre[maxn],dist[maxn],g[maxn][maxn],edgeNum,first[maxn]; void Addedge(int u,int v,int w) { e[edgeNum].u=u,e[edgeNum].v=v,e[edgeNum].w=w,e[edgeNum].next=first[u],first[u]=edgeNum++; e[edgeNum].u=v,e[edgeNum].v=u,e[edgeNum].w=0,e[edgeNum].next=first[v],first[v]=edgeNum++; } bool Dinic_Label() { int i,j,k,head=0,tail=0,q[maxn]; memset(pre,-1,sizeof(pre)); memset(dist,0,sizeof(dist)); q[tail++]=S; dist[S]=1; while(head!=tail) { k=q[head]; head=(head+1)%maxn; for(i=first[k];i!=-1;i=e[i].next) { j=e[i].v; if(e[i].w>0&&!dist[j])//注意这里有e[i].w>0 { dist[j]=dist[k]+1; if(j==T) return true; q[tail]=j; tail=(tail+1)%maxn; } } } return false; } int Dinic_Augment(int s) { int i,j,min,sum; if(s==T) { for(min=maxint,i=pre[T];i!=-1;i=pre[e[i].u])//注意i=pre[e[i].u]而不是i=pre[i] if(min>e[i].w) min=e[i].w; for(i=pre[T];i!=-1;i=pre[e[i].u])// { e[i].w-=min; e[i^1].w+=min;//是^,而不是+1,-1 } return min; } for(sum=0,i=first[s];i!=-1;i=e[i].next) { j=e[i].v; if(e[i].w>0&&dist[s]+1==dist[j])//e[i].w>0和dist[s]+1==dist[j]缺一不可 { pre[j]=i; sum+=Dinic_Augment(j); } } return sum; } int Dinic() { int sum=0; while(Dinic_Label()) sum+=Dinic_Augment(S); return sum; } int main() { int i,j,k,sum,sum1; while(scanf("%d",&n)!=EOF) { for(i=0;i<n;i++) scanf("%d",&a[i]); for(i=0;i<n;i++) scanf("%d",&b[i]); k=a[0]+b[0]; S=0,T=430; edgeNum=0; memset(first,-1,sizeof(first)); for(sum=0,sum1=0,i=0;i<n;i++) for(j=0;j<n;j++) { scanf("%d",&g[i][j]); if(i&&i<j&&g[i][j]) { Addedge(i,sum+n,g[i][j]); Addedge(j,sum+n,g[i][j]); Addedge(sum+n,T,g[i][j]); sum++; sum1+=g[i][j]; } } for(i=1;i<n;i++) { if(k<a[i]) { printf("NO\n"); break; } else Addedge(S,i,k-a[i]); } if(i<n) continue; if(Dinic()==sum1) printf("YES\n"); else printf("NO\n"); } return 0; }