题目地址:http://acm.sgu.ru/problem.php?contest=0&problem=326
额,这题读错题了。。。又WA了好长时间。。。坚持不看题解也挺浪费时间的。。早点看题解不自己憋着就能早就发现这个傻逼错误了。。。我的错误是把第三行输入的值误认为是只有跨赛区的比赛了,其实后面的括号里很明显写着包括同赛区的比赛。。但是我不认识。。又懒得翻译。。于是这个傻逼错误就诞生了。。。
这题有一种贪心的思想,就是让队伍1的跨赛区比赛尽可能获胜,其他队伍的跨赛区比赛尽可能输。然后算出此时队伍1与其他队伍的积分差值。
建图方法是建立一个源点与一个汇点,把每一场比赛单独看作一个单位,将比赛与源点连边,权值为这场比赛的比赛数。将每场比赛与比赛双方连边,这个权值可以为无限大,只要大于比赛数就可以。最后将每个队与汇点连边,权值为这个队要想不超过队伍1的最大可能分数,即与队伍1的积分差值。最后求最大流是否满流。
代码如下:
#include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <queue> #include <map> #include<algorithm> using namespace std; const int INF=0x3f3f3f3f; int head[500], souce, sink, nv, cnt; int cur[500], num[500], d[500], q[500], p[50], mp[30][30], pre[500]; struct node { int u, v, cap, next; } edge[1000000]; void add(int u, int v, int cap) { edge[cnt].v=v; edge[cnt].cap=cap; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].v=u; edge[cnt].cap=0; edge[cnt].next=head[v]; head[v]=cnt++; } void bfs() { memset(num,0,sizeof(num)); memset(d,-1,sizeof(d)); int f1=0, f2=0, i; d[sink]=0; num[0]=1; q[f1++]=sink; while(f1>=f2) { int u=q[f2++]; for(i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(d[v]==-1) { d[v]=d[u]+1; num[d[v]]++; q[f1++]=v; } } } } int isap() { memcpy(cur,head,sizeof(cur)); bfs(); int flow=0, u=pre[souce]=souce, i; while(d[souce]<nv) { if(u==sink) { int f=INF, pos; for(i=souce;i!=sink;i=edge[cur[i]].v) { if(f>edge[cur[i]].cap) { f=edge[cur[i]].cap; pos=i; } } for(i=souce;i!=sink;i=edge[cur[i]].v) { edge[cur[i]].cap-=f; edge[cur[i]^1].cap+=f; } flow+=f; u=pos; } for(i=cur[u];i!=-1;i=edge[i].next) { if(d[edge[i].v]+1==d[u]&&edge[i].cap) break; } if(i!=-1) { cur[u]=i; pre[edge[i].v]=u; u=edge[i].v; } else { if(--num[d[u]]==0) break; int mind=nv; for(i=head[u];i!=-1;i=edge[i].next) { if(mind>d[edge[i].v]&&edge[i].cap) { mind=d[edge[i].v]; cur[u]=i; } } d[u]=mind+1; num[d[u]]++; u=pre[u]; } } return flow; } int main() { int n, x, i, j, flag=0, s=0, sum=0, ss; memset(head,-1,sizeof(head)); cnt=0; scanf("%d",&n); for(i=1; i<=n; i++) scanf("%d",&p[i]); scanf("%d",&x); p[1]+=x; for(i=1; i<n; i++) scanf("%d",&x); for(i=2; i<=n; i++) { if(p[i]>p[1]) { flag=1; break; } } if(flag) { printf("NO\n"); } else { for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { scanf("%d",&mp[i][j]); if(mp[i][j]&&i!=1&&j!=1&&j<i) { s++; add(0,s,mp[i][j]); sum+=mp[i][j]; } } } //for(i=1;i<=n;i++) // p[1]+=mp[1][i]; souce=0; sink=s+n+1; nv=sink+1; ss=0; for(i=2;i<=n;i++) { add(s+i,sink,p[1]-p[i]); for(j=2;j<i;j++) { if(mp[i][j]) { ss++; add(ss,i+s,mp[i][j]); add(ss,j+s,mp[i][j]); } } } x=isap(); if(x>=sum) printf("YES\n"); else printf("NO\n"); } return 0; }