bzoj4663 Hack
来源:互联网 发布:linux设置时间 编辑:程序博客网 时间:2024/06/05 18:27
题目链接:bzoj4663
题目大意:
给你一个有向图,hack一条边需要一定的代价。要求从0到n-1的每条路径上有且只有一条边被hack到。问最小代价。
题解:
最小割
不知道怎么搞一条路径只能有一条边被割的限制Orz
%%%HYC(她说她去膜了大胖子还不让我膜她 我就膜2333
不考虑只能有一条边被割的限制的话就直接按原图建边求最小割就好了。
而一条路径上正常情况下因为是最小割,所以只会有一条边会被割。那么如果有两条边被割了的话就只会是类似于这样(看图)的情况:
怎么让它不会这样割,即使得这样割没有用呢?
加让每条边都加一条流量为inf的反向边就好了(其实可以直接改网络流中原来要建的流量为0的边的流量)。那么图就变成了这样:
S和T仍然连通,即使这样的割法无效。
哦,注意,要先把不能从S出发到达的点和边删掉再来构图。
#include<cstdio>#include<cstdlib>#include<cstring>#include<queue>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;#define maxn 110#define maxm 5100const LL inf=1e15;struct node{ int x,y,ot,next;bool p;LL c;}a[maxm*2];int len,first[maxn];void ins(int x,int y,LL c){ len++;int n1=len;a[len].x=x;a[len].y=y; a[len].c=c;a[len].next=first[x];first[x]=len; len++;int n2=len;a[len].x=y;a[len].y=x; a[len].c=inf;a[len].next=first[y];first[y]=len; a[n1].p=a[n2].p=0;a[n1].ot=n2;a[n2].ot=n1;}queue<int> q;int S,T,d[maxn];bool vis[maxn];LL mymin(LL x,LL y){return (x<y)?x:y;}bool bfs(){ memset(d,-1,sizeof(d)); memset(vis,false,sizeof(vis)); d[S]=0;vis[S]=true;q.push(S); while (!q.empty()) { int x=q.front();q.pop(); for (int k=first[x];k!=-1;k=a[k].next) { int y=a[k].y; if (a[k].c<=0 || !a[k].p) continue; if (d[y]==-1) { d[y]=d[x]+1; if (!vis[y]) { vis[y]=true; q.push(y); } } }vis[x]=false; } return d[T]!=-1;}LL dfs(int x,LL flow){ if (x==T) return flow; LL delta=0; for (int k=first[x];k!=-1;k=a[k].next) { int y=a[k].y; if (a[k].c<=0 || !a[k].p) continue; if (d[y]==d[x]+1) { LL minf=mymin(a[k].c,flow-delta); minf=dfs(y,minf); a[k].c-=minf; a[a[k].ot].c+=minf; delta+=minf; if (delta==flow) break; } }if (delta==0) d[x]=-1; return delta;}LL dinic(){ LL ret=0; while (bfs()) { ret+=dfs(S,inf); if (ret>inf) break; } if (ret>inf) return -1; return ret;}void getout(int x,int fa){ vis[x]=true; for (int k=first[x];k!=-1;k=a[k].next) if (k&1) { int y=a[k].y; if (y==fa) continue; if (!vis[y]) getout(y,x); } }int main(){ //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); int n,m,i,u,v;LL w; scanf("%d%d",&n,&m); len=0;memset(first,-1,sizeof(first)); for (i=1;i<=m;i++) { scanf("%d%d%lld",&u,&v,&w); u++;v++;ins(u,v,w); } S=1;T=n;getout(S,0); for (i=1;i<=len;i+=2) if (vis[a[i].x] && vis[a[i].y]) a[i].p=a[a[i].ot].p=true; printf("%lld\n",dinic()); return 0;}
0 0
- bzoj4663 Hack
- BZOJ4663: Hack
- HACK
- HACK
- hack
- Hack
- hack
- hack
- hack
- hack
- HACK
- hack
- hack
- 【Hack】ie 条件Hack
- Google Hack
- XOOPS HACK
- Cocoa Hack
- Hack Game
- Elastic-Job项目源码分析5 -- 事件追踪
- 正向代理和反向代理
- Java中常用文件IO流类:FileInputStream和FileOutputStream
- c++实验4-项目6
- grunt自动刷新liveload
- bzoj4663 Hack
- unity 2d贴图
- Centos7上的yum命令
- layaAir学习之一:创建空项目----js方向
- 顺序表实现集合及大整数运算
- linux 生成ssl证书
- java项目类型---java新手
- 每天一个linux命令(30): chown命令
- 如何理解c++中的引用折叠?