1532: [POI2005]Kos-Dicing
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1577 Solved: 542
[ Submit][ Status][ Discuss]
Description
Dicing 是一个两人玩的游戏,这个游戏在Byteotia非常流行. 甚至人们专门成立了这个游戏的一个俱乐部. 俱乐部的人时常在一起玩这个游戏然后评选出玩得最好的人.现在有一个非常不走运的家伙,他想成为那个玩的最好的人,他现在知道了所有比赛的安排,他想知道,在最好的情况下,他最少只需要赢几场就可以赢得冠军,即他想知道比赛以后赢的最多的那个家伙最少会赢多少场.
Input
第一行两个整数n 和 m, 1 <= n <= 10 000, 0 <= m <= 10 000; n 表示一共有多少个参赛者, m 表示有多少场比赛. 选手从1 到 n编号. 接下来m 行每行两个整数表示该场比赛的两个选手,两个选手可能比赛多场.
Output
第一行表示赢得最多的人最少会赢多少场
Sample Input
4 4
1 2
1 3
1 4
1 2
1 2
1 3
1 4
1 2
Sample Output
1
HINT
Source
题解:二分+最大流
二分一个最大的获胜数mid,最大流判断是否可行
s->每场比赛 容量为1
每场比赛->该场比赛的两名选手 容量为1
每位选手->T 容量为1
看最后的是否满流即可。
这道题卡isap,差评。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<cmath>
#define N 100003
#define inf 1000000000
using namespace std;
int x[N],y[N],n,m;
int tot,point[N],nxt[N],v[N],remain[N],lst[N],num[N];
int deep[N],cur[N];
void add(int x,int y,int z)
{
tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z;
tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0;
}
bool bfs(int s,int t)
{
memset(deep,0x7f,sizeof(deep));
for (int i=1;i<=t;i++)
cur[i]=point[i];
deep[1]=0;
queue<int> p;
p.push(1);
while (!p.empty())
{
int now=p.front(); p.pop();
for (int i=point[now];i!=-1;i=nxt[i])
{
if(deep[v[i]]>inf&&remain[i])
{
deep[v[i]]=deep[now]+1;
p.push(v[i]);
}
}
}
if (deep[t]>inf) return false;
else return true;
}
int dfs(int now,int t,int limit)
{
if (now==t||!limit) return limit;
int flow=0,f;
for (int i=cur[now];i!=-1;i=nxt[i])
{
cur[now]=i;
if (deep[v[i]]==deep[now]+1&&(f=dfs(v[i],t,min(limit,remain[i]))))
{
flow+=f; limit-=f;
remain[i]-=f; remain[i^1]+=f;
if (!limit) break;
}
}
return flow;
}
int dinic(int s,int t)
{
int ans=0;
while(bfs(s,t))
ans+=dfs(s,t,inf);
return ans;
}
bool check(int mid)
{
tot=-1;
memset(point,-1,sizeof(point));
memset(num,0,sizeof(num));
int s=1; int t=n+m+2;
for (int i=1;i<=m;i++) {
add(s,i+1,1);
add(i+1,x[i]+m+1,1);
add(i+1,y[i]+m+1,1);
}
for (int i=1;i<=n;i++) add(i+m+1,t,mid);
return dinic(s,t)==m;
}
int main()
{
freopen("a.in","r",stdin);
//freopen("game.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++) scanf("%d%d",&x[i],&y[i]);
int l=1; int r=m; int ans=m;
while (l<=r) {
int mid=(l+r)/2;
if (check(mid)) ans=min(ans,mid),r=mid-1;
else l=mid+1;
}
printf("%d\n",ans);
}