題意:現一個隊有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;
}