[COGS329] K- 联赛

算是一道巧妙的最大流问题问题吧
对于每个队伍用最大流求出它是否可以获胜
具体将每两个队伍i,j间的比赛作为点 c ,
Sccap=ai,j
c icap=infi
c jcap=infi
表示有 a[i][j] 个胜利需要分配给 i j
再对每个队伍 i
iTcap=Wnow+SnowWi
表示他得到的总胜利不能超过当前询问的队伍 now 的胜利次数,
最大流判断是否存在方案.

/****************************************\
* Author : ztx
* Title  : [cogs] 329 K- 联赛
* ALG    : 网络流
* CMT    :
对于每个队伍用最大流求出它是否可以获胜
具体将每两个队伍i,j间的比赛作为点c,
S->c a[i][j]
c->i infi
c->j infi
表示有a[i][j]个胜利需要分配给i与j
再对每个队伍i
i->T W[now]+S[now]-W[i]
表示他得到的总胜利不能超过当前询问的队伍now的胜利次数,
最大流判断是否存在方案.
* Time   :
\****************************************/

#include <cstdio>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
typedef long long ll ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
    ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
    if (CH == '-') NEG = true , CH = getchar() ;
    while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
    if (NEG) ret = -ret ;
}
template <typename TP>inline void readc(TP& ret) {
    while (ret=getchar() , ret<'!') ;
    while (CH=getchar() , CH>'!') ;
}
template <typename TP>inline void reads(TP *ret) {
    ret[0]=0;while (CH=getchar() , CH<'!') ;
    while (ret[++ret[0]]=CH,CH=getchar(),CH>'!') ;
    ret[ret[0]+1]=0;
}

#include <cstring>

#define  maxn  26LL
int n,sum,w[maxn],a[maxn][maxn],s[maxn];

#define  maxN  666LL
#define  min(x,y) ((x)<(y)?(x):(y))
#define  infi  0x7f7f7f7fLL
int g[maxN][maxN] ;
int N , S , T , h[maxN] , vh[maxN] ;
inline void Edge_init() { memset(g , 0 , sizeof g) ; }
inline void Edge_add(int u,int v,int f) { g[u][v] = f , g[v][u] = 0 ; }

int dfs(int u,int flowu) {
int v,flow,flowv,tmp = h[u]+1 ;
    if (u == T) return flowu ;
    flow = 0 ;
    Rep (v,1,N) if (g[u][v] && h[u]==h[v]+1) {
        flowv = dfs(v,min(flowu-flow,g[u][v])) ;
        flow += flowv , g[u][v] -= flowv , g[v][u] += flowv ;
        if (flow==flowu || h[S]==N) return flow ;
    }
    Rep (v,1,N) if (g[u][v] && h[v]<tmp)
        tmp = h[v] ;
    if (--vh[h[u]]==0) h[S] = N ;
    else ++vh[h[u]=tmp+1] ;
    return flow ;
}
inline void sap(int now) {
int maxflow = 0 , i , j , c = 0 ;
    Edge_init() ;
    Rep (i,1,n) if (w[i]>w[now]+s[now])
        return ;
    Rep (i,1,n) if (i!=now)
        Rep (j,i+1,n) if (j!=now && a[i][j])
            c++ ;
    S = n+c+1 , T = N = S+1 ;
    c = 0 ;
    Rep (i,1,n) if (i!=now)
        Edge_add(i,T,w[now]+s[now]-w[i]) ;
    Rep (i,1,n) if (i!=now)
        Rep (j,i+1,n) if (j!=now && a[i][j]) {
            c ++ ;
            Edge_add(S,n+c,a[i][j]) ;
            Edge_add(n+c,i,infi) ;
            Edge_add(n+c,j,infi) ;
        }
    memset(h,0,sizeof h) ;
    memset(vh,0,sizeof vh) ;
    vh[S] = N ;
    while (h[S] < N) maxflow += dfs(S , infi) ;
    if (maxflow == sum-s[now]) printf("%d ",now) ;
    return ;
}


int main() {
int i , j ;
    #define READ
    #ifdef  READ
        freopen("kleague.in" ,"r",stdin ) ;
        freopen("kleague.out","w",stdout) ;
    #endif
    read(n) ;
    Rep (i,1,n)
        read(w[i]) , read(j) ;
    sum = 0 ;
    Rep (i,1,n) {
        s[i] = 0 ;
        Rep (j,1,n) {
            read(a[i][j]) ;
            s[i] += a[i][j] ;
            sum += a[i][j] ;
        }
    }
    sum >>= 1 ;
    Rep (i,1,n) sap(i) ;
    puts("") ;
    #ifdef  READ
        fclose(stdin) ; fclose(stdout) ;
    #else
        getchar() ; getchar() ;
    #endif
    return 0 ;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值