///过的代码
zoj 3229 分数规划
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 308
#define edge 20800
#define inf 0x3f3f3f3f
#define eps 1e-5
int first[maxn],dis[maxn],num[maxn],du[maxn];
int vv[edge],nxt[edge];
double ww[edge];
bool vis[maxn];
int e,NN,n,m;
int sum = 0;
int ta[2000],tb[2000];
struct Edge
{
int u,v;
Edge(){}
Edge(int uu,int vv)
{
u = uu;v = vv;
}
};
void addedge(int u,int v,double w)//添加单向边
{
vv[e] = v; ww[e] = w; nxt[e] = first[u]; first[u] = e++;
vv[e] = u; ww[e] = 0; nxt[e] = first[v]; first[v] = e++;
}
void addEdge(int u,int v,double w)//添加双向边
{
vv[e] = v; ww[e] = w; nxt[e] = first[u]; first[u] = e++;
vv[e] = u; ww[e] = w; nxt[e] = first[v]; first[v] = e++;
}
inline double min(double a,double b)
{
return a>b?b:a;
}
double dfs(int u,int s,int d,double cost)
{
if(u == d) return cost;
double ans = 0;
int _min = NN;
for(int i = first[u];i != -1;i = nxt[i])
{
int v = vv[i];
if(ww[i] > eps)
{
if(dis[v] + 1 == dis[u])
{
double t = dfs(v,s,d,min(ww[i],cost));
ww[i] -= t;
ww[i^1] += t;
ans += t;
cost -= t;
if(dis[s] == NN) return ans;
if(cost <= eps) break;
}
if(_min > dis[v]) _min = dis[v];
}
}
if(ans <= eps)
{
if(--num[dis[u]] == 0) dis[s] = NN;
dis[u] = _min + 1;
++num[dis[u]];
}
return ans;
}
double isap(int s,int d)
{
memset(dis,0,sizeof(dis));
memset(num,0,sizeof(num));
num[0] = NN;
double ans = 0;
while(dis[s] < NN) ans += dfs(s,s,d,inf);
return ans;
}
void build(double g)
{
e = 0;NN = n + 2;
memset(first,-1,sizeof(first));
for(int i = 1;i <= n;i++)
{
addedge(0,i,m);
}
for(int i = 1;i <= m;i++)
{
addEdge(ta[i],tb[i],1);
}
for(int i = 1;i <= n;i++)
{
addedge(i,n+1,m+2*g-du[i]);
}
}
void dfs(int u)///遍历图
{
vis[u] = 1;
for(int i = first[u];i != -1;i = nxt[i])
{
int v = vv[i];
if(ww[i] > 0 && !vis[v])
{
vis[v] = 1;
sum++;
dfs(v);
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m)==2)
{
if(m == 0)
{
printf("%d\n%d\n",1,1);
continue;
}
memset(du,0,sizeof(du));
for(int i = 1;i <= m;i++)
{
scanf("%d%d",&ta[i],&tb[i]);
du[ta[i]]++;du[tb[i]]++;
}
double l = 0,r = m;
while(r - l >= 1./n/n)
{
double mid = (l + r)/2;
build(mid);
if((m*n - isap(0,n+1))/2 > eps)
{
l = mid;
}
else r = mid;
}
build(l);
memset(vis,0,sizeof(vis));
isap(0,n+1);
sum = 0;
dfs(0);
int ok = 0;
printf("%d\n",sum);
for(int i = 1;i <= n;i++)
{
if(vis[i])
{
printf("%d\n",i);
}
}
}
return 0;
}
ZOJ 3229 有源有汇上下界最大流
最新推荐文章于 2021-03-30 13:15:57 发布