SGU 326 网络流

题目大意:NBA 某小组内有 N 支球队,小组内以及小组间已经进行了若干场比赛。现在给
出这 N 支球队目前胜利的场数、还剩多少场没有比(包括小组内和小组间)以
及小组内任意两支球队之间还剩多少场没有比,问能否合理安排剩下的所有比赛,
使得球队 1 最后胜利的场数至少和小组内任何一支其他球队一样。
(2 <= N <= 20,
0 <= x <= 10000, x 表示其他任何输入)

同样,所有和球队 1 相关的比赛全让球队 1 赢,如果此
时仍有某支球队胜利的场数大于球队 1,则已经不可能满足要求。按如下方法建
图:所有小组内的比赛 i(不包括与球队 1 相关的比赛)作为一个点并加边(s, i,
num[i]),每支球队(不包括球队 1)作为一个点并加边(j, t, wins[1]-wins[i]),每场
比赛向与其关联的两支球队 u, v 连边(i, u, ∞), (i, v, ∞)。至于其他球队小组间的
比赛,直接让他们输掉就好,不用管。若最大流等于∑num[i]则可以满足要求。

ps:此类比赛的问题一般将比赛和球队作为点,源点向每个比赛的点连一条场数的边,每个比赛向参加比赛的球队连边(流量视情况而定),然后每个球队向汇点连一条边,流量即为该球队胜场的限制.

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<set>
#include<vector>
#include<cmath>
#include<map>
#include<queue>
#define LL long long
using namespace std;
const LL mod=1e9+7;
const int N=1e3+5;
const int inf=0x3f3f3f3f;
struct node
{
    int to,cap,next,flow;
    node(){}
    node(int to,int cap,int next,int flow):to(to),cap(cap),next(next),flow(flow){}
}edge[N<<2];
int tol;
int head[N],gap[N],dep[N],pre[N],cur[N];
int win[N],r[N],a[N][N];
void init()
{
   tol=0;
   memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w,int rw=0)
{
    edge[tol]=node(v,w,head[u],0);
    head[u]=tol++;
    edge[tol]=node(u,rw,head[v],0);
    head[v]=tol++;
}
int sap(int start,int _end,int N)
{
    memset(gap,0,sizeof(gap));
    memset(dep,0,sizeof(dep));
    memcpy(cur,head,sizeof(head));
    int u=start;
    pre[u]=-1;
    gap[0]=N;
    int ans=0;
    while(dep[start]<N)
    {
        if(u==_end)
        {
            int Min=inf;
            for(int i=pre[u];i!=-1;i=pre[edge[i^1].to])
               if(Min>edge[i].cap-edge[i].flow)
                  Min=edge[i].cap-edge[i].flow;
            for(int i=pre[u];i!=-1;i=pre[edge[i^1].to])
            {
                edge[i].flow+=Min;
                edge[i^1].flow-=Min;
            }
            u=start;
            ans+=Min;
            continue;
        }
        bool flag=false;
        int v;
        for(int i=cur[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].to;
            if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u])
            {
                flag=true;
                cur[u]=pre[v]=i;
                break;
            }
        }
        if(flag)
        {
            u=v;
            continue;
        }
        int Min=N;
        for(int i=head[u];i!=-1;i=edge[i].next)
            if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min)
            {
                Min=dep[edge[i].to];
                cur[u]=i;
            }
        gap[dep[u]]--;
        if(!gap[dep[u]])return ans;
        dep[u]=Min+1;
        gap[dep[u]]++;
        if(u!=start)u=edge[pre[u]^1].to;

    }
    return ans;
}
int main()
{
    //freopen("a.txt","r",stdin);
    int n;
    while(~scanf("%d",&n))
    {
        init();
        for(int i=1;i<=n;i++)scanf("%d",&win[i]);
        for(int i=1;i<=n;i++)scanf("%d",&r[i]);
        for(int i=1;i<=n;i++)
           for(int j=1;j<=n;j++)
           scanf("%d",&a[i][j]);
        int temp=win[1]+r[1];
        int flag=1;
        for(int i=2;i<=n;i++)
           if(win[i]>temp)flag=0;
        if(flag==0)
        {
            puts("NO");continue;
        }
        int cnt=0,sum=0;
        for(int i=2;i<=n;i++)
        {
           for(int j=i;j<=n;j++)
           {
               cnt++;sum+=a[i][j];
               addedge(0,cnt,a[i][j]);
               addedge(cnt,i-1+n*(n-1)/2,inf);
               addedge(cnt,j-1+n*(n-1)/2,inf);
           }
        }
        for(int i=2;i<=n;i++)
            addedge(i-1+n*(n-1)/2,n*(n+1)/2,temp-win[i]);
        int ans=sap(0,n*(n+1)/2,n*(n+1)/2+1);
        if(ans==sum)puts("YES");
        else puts("NO");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值