1 条题解
-
0
二分+网络流
- 看到"最大值最小",显然要二分最少赢多少场。
- 源点向每一个比赛连一条流量为1的边,表明每个比赛只能赢一次
- 每个比赛向2位选手各连一条流量为1的边,表明每个比赛只能有一个人赢
- 最后每个选手向汇点连一条流量为mid的边,如果总流量>=比赛数,那么这个做法可行
- 等等,要输出方案!
- 每一个比赛向哪一个选手连的边流量是1,就代表这个选手赢了
- 好吧,下面就是我的code
#include<bits/stdc++.h> using namespace std; const int N=1e5+10; const int p=2e4; const int inf=0x3f3f3f3f; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*f; } int n,m,U[N],V[N],de[N],first[N],cur[N],cnt,dis[N],s,t; struct node{ int v,w,nxt; }e[N]; inline void add(int u,int v,int w){ e[++cnt].v=v;e[cnt].w=w; e[cnt].nxt=first[u];first[u]=cnt; } inline int bfs(){ queue<int>q; memset(dis,-1,sizeof(dis)); dis[s]=0; q.push(s); while(!q.empty()){ int u=q.front(); q.pop(); for(int i=first[u];i;i=e[i].nxt){ int v=e[i].v; if(e[i].w>0&&dis[v]==-1){ dis[v]=dis[u]+1; q.push(v); if(v==t) return 1; } } } return 0; } inline int dfs(int x,int f){ if(x==t||f==0) return f; int used=0; for(int& i=cur[x];i;i=e[i].nxt){ if(e[i].w&&dis[e[i].v]==dis[x]+1){ int w=dfs(e[i].v,min(f,e[i].w)); if(!w) continue; used+=w; f-=w; e[i].w-=w; e[i^1].w+=w; if(f==0) break; } } if(!used) dis[x]=-1; return used; } inline int dinic(){ int ans=0; while(bfs()){ memcpy(cur,first,sizeof(first)); ans+=dfs(s,inf); } return ans; }//网络流板子 inline int check(int x){ memset(first,0,sizeof(first)); cnt=1;s=n+p+1,t=s+1; for(int i=1;i<=m;i++){ add(s,i,1);add(i,s,0); add(i,U[i]+p,1);add(U[i]+p,i,0); add(i,V[i]+p,1);add(V[i]+p,i,0); } for(int i=1;i<=n;i++) add(i+p,t,x),add(t,i+p,0); return dinic()>=m; }//本题的重点:建图 inline int Print(){ for(int i=0;i<m;i++){ if(e[i*6+4].w==0) puts("1"); else puts("0"); } }//打印方案 int main(){ n=read();m=read(); for(int i=1;i<=m;i++) U[i]=read(),V[i]=read(); int l=m/n,r=m; while(l<r){ int mid=(l+r)>>1; if(check(mid)) r=mid; else l=mid+1; }//二分 printf("%d\n",l); check(l); Print(); return 0; }
- 1
信息
- ID
- 3187
- 时间
- 1000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 10
- 已通过
- 1
- 上传者