1. 程式人生 > >[POI2005]KOS-Dicing (最大流+二分)lg3425

[POI2005]KOS-Dicing (最大流+二分)lg3425

 題面https://www.luogu.org/problemnew/show/P3425

題面說贏的最多的人最少贏幾場,肯定是向二分的方向思考

建立源點向每一場比賽連容量為1的邊,從每場比賽向參賽兩個人各連一條容量為1的邊,表示一場比賽有一個人贏

二分一個最多的人贏的場數,從每個人向匯點連容量為mid的邊,若最大流等於場數,說明符合題意,可以減小最多的人贏的場數,反之縮小

因為要輸出方案,可以記錄下滿足條件的最小答案,然後以這個答案再跑一次,從比賽流向個人的邊如果容量為0(也就是在增廣時被流過了)說明他贏了這場比賽

#include<bits/stdc++.h>
#include
<queue> using namespace std; #define INF 0x3f3f3f3f inline int read(){ int w=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ w=(w<<3)+(w<<1)+ch-48; ch=getchar(); }
return w*f; } int n,m,cnt=-1,head[100010],cur[100010],depth[100010],S,T,u[100010],v[100010],ans,x[100010],y[100010]; const int p=10000; bool vis[100010]; struct Edge{ int from,to,next,flow; }edge[1000010]; inline void addedge(int u,int v,int w){ cnt++; edge[cnt].from=u; edge[cnt].to=v; edge[cnt].flow=w; edge[cnt].next
=head[u]; head[u]=cnt; } inline void ins(int u,int v,int w){ addedge(u,v,w);addedge(v,u,0); } queue<int> q; inline bool bfs(int st,int ed){ memset(depth,0,sizeof(depth)); int u,v,i,j,k;q.push(st);depth[st]=1; for(i=S;i<=T;i++)cur[i]=head[i]; while(!q.empty()){ u=q.front();q.pop(); for(i=head[u];i!=-1;i=edge[i].next){ v=edge[i].to; if(!depth[v]&&edge[i].flow){ depth[v]=depth[u]+1;q.push(v); } } } return depth[ed]; } inline int dfs(int u,int ed,int limit){ if(!limit||u==ed) return limit; int v,i,j,k;int flow=0,f; for(i=cur[u];i!=-1;i=edge[i].next){ v=edge[i].to;cur[u]=i; if(depth[v]==depth[u]+1&&(f=dfs(v,ed,min(limit,edge[i].flow)))){ limit-=f;flow+=f; edge[i].flow-=f;edge[i^1].flow+=f; if(!limit) break; } } return flow; } inline void Dinic(){ while(bfs(S,T)){ ans+=dfs(S,T,INF); } } inline bool check(int mid){ cnt=-1;memset(head,-1,sizeof(head)); int i,j,k; for(i=1;i<=m;i++){ ins(S,i,1); ins(i,x[i]+p,1); ins(i,y[i]+p,1); } for(i=1;i<=n;i++){ ins(i+p,T,mid); } ans=0;Dinic(); return ans==m; } int main(){ n=read();m=read();int i,j,k;int ans1; memset(head,-1,sizeof(head));S=0;T=99999; for(i=1;i<=m;i++){ x[i]=read();y[i]=read(); } int l=0,r=m+1; while(l<=r){ int mid=(l+r)>>1; if(check(mid)) r=mid-1,ans1=mid; else l=mid+1; } cout<<ans1<<endl; check(ans1); for(int u=1;u<=m;u++){ for(i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to;v-=p;if(v<1 or edge[i].flow) continue; if(v==x[u]) vis[u]=true; } } for(i=1;i<=m;i++){ printf("%d\n",vis[i]); } return 0; }