BZOJ 4501: 旅行 01分数规划 最大权闭合子图

来源:互联网 发布:网络硬盘服务器 编辑:程序博客网 时间:2024/05/16 07:11

4501: 旅行

Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special Judge
Submit: 169  Solved: 75
[Submit][Status][Discuss]

Description

小C来到了F国,小C想好好地参观F国。F国可以看一个有n个点m条边的有向无环图,小C刚开始站在1号点。假设现在小C站在x号点:
1.点x没有出边,结束旅游。
2.点x有o条出边,小C等概率地选一条边走过去。
小J是小C的好朋友,小J可以使用魔法让一些边消失,但是有一些限制(x,y):第y条边如果被删掉了,那么第x条边也会受到影响,导致x条边被删掉。
现在小J想知道,如何删边使得小C所经过的边数期望最大。

Input

第一行三个整数,n,m,k(1 <= n <= 50, 0 <= m <= 500, 0 <= k <= 2000),代表有n个点,m条边,k个限制。
接下来m行,第i行代表第i条边x,y(1 <= x, y <= n),方向是从x到y。
接下来k行,每行有两个整数x,y(1 <= x, y <= m),代表限制。
保证图是有向无环的,保证对于每个限制(x,y),第x条边和第y条边的起点是相同的。可能有重边,限制可能重复。1 <= n <= 50, 0 <= m <= 500, 0 <= k <= 2000

Output

输出一个实数,最大的边数期望。只要和标准答案误差小于10^-2 就认为是相同的。

Sample Input

3 3 0
1 2
1 3
2 3

Sample Output

2.0000000

这道题读错了两遍。。。

首先啊 x,y的起点相同 所以说 每个点的边之间不会互相影响

所以 我们按拓扑序由后向前解决每一个点 令每一个点最优 答案一定最优

现在对于一个节点

我们令b[i]表由该点经过一个儿子节点i向下最多的边数期望

a[i]表示该点选不选 则答案如下

这时 下一步就很明显了

式子显然是 01分数规划的形式

那么二分答案就好


可是怎么判定呢?

老套路移项就好了

这时该怎么做呢

考虑

这些边之间存在没有y就一定没有x的情况 即有x就一定有y

那么 最大权闭合子图

之后 就结束啦


#include<cmath>#include<ctime>#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#include<iomanip>#include<vector>#include<string>#include<bitset>#include<queue>#include<set>#include<map>using namespace std;typedef long long ll;typedef double db;inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return f*x;}void print(int x){if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}const int N=55,M=510,inf=0X3f3f3f3f;const db eps=1e-9;int S=M-2,T=M-1;namespace flow{int last[M],ecnt;struct EDGE{int to,nt;db val;}e[M*M];inline void readd(int u,int v,db val){e[++ecnt]=(EDGE){v,last[u],val};last[u]=ecnt;}inline void add(int u,int v,db val){readd(u,v,val);readd(v,u,0);}int d[M],q[M];bool bfs(){memset(d,0,sizeof(d));int head=0,tail=1;d[S]=1;q[head]=S;while(head<tail){int u=q[head++];for(int i=last[u];i;i=e[i].nt)if(e[i].val>eps&&!d[e[i].to]){d[e[i].to]=d[u]+1;q[tail++]=e[i].to;}}return d[T];}db dfs(int u,db lim){if(u==T)return lim;db res=0;for(int i=last[u];i;i=e[i].nt)if(d[e[i].to]==d[u]+1&&e[i].val){db tmp=dfs(e[i].to,min(e[i].val,lim));res+=tmp;lim-=tmp;e[i].val-=tmp;e[i^1].val+=tmp;if(tmp<eps)d[e[i].to]=-1;if(lim<eps)break;}return res;}db mxflow;db dinic(){while(bfs())mxflow+=dfs(S,inf);return mxflow;}void init(){memset(last,0,sizeof(last));ecnt=1;mxflow=0;}}int last[N],ecnt;struct EDGE{int to,nt;}e[M];inline void add(int u,int v){e[++ecnt]=(EDGE){v,last[u]};last[u]=ecnt;}db f[N];bool vis[N];vector<int>vec[M];void topo(int u){if(vis[u])return ;vis[u]=1;db l=0,r=0,mid;for(int i=last[u];i;i=e[i].nt){topo(e[i].to);r=max(r,f[e[i].to]+1);}while(r-l>eps){mid=(l+r)/2.0;flow::init();db res=0;for(int i=last[u];i;i=e[i].nt){for(int j=0;j<vec[i].size();++j)flow::add(i,vec[i][j],inf);if(f[e[i].to]+1-mid<0)flow::add(S,i,mid-f[e[i].to]-1);elseres+=f[e[i].to]+1-mid,flow::add(i,T,f[e[i].to]+1-mid);}res-=flow::dinic();res>eps?(f[u]=mid,l=mid):r=mid;}}int main(){int n=read(),m=read(),K=read();register int i,u,v;for(i=1;i<=m;++i){u=read();v=read();add(u,v);}for(i=1;i<=K;++i){u=read();v=read();vec[v].push_back(u);}topo(1);printf("%.10lf",f[1]);return 0;}

原创粉丝点击