HDU 3488 Tour 最小费用最大流||最大匹配
2014-05-07 13:47
459 查看
题意:选一条路线,使得经过n条路,并且有环,回到起点
分析:n条路分别从n个不同的点出发,到达不同的点,用最大匹配可解
把每个点拆成2个,一个进,一个出,连接源点跟所有进入点,容量为1,费用为0,连接所以出点和汇点,容量为1,费用为0
对于每条边(u,v,w),连接u,v+n,容量为1,费用为w;
费用流
将值取反,求最大匹配,注意INF不能过大
分析:n条路分别从n个不同的点出发,到达不同的点,用最大匹配可解
把每个点拆成2个,一个进,一个出,连接源点跟所有进入点,容量为1,费用为0,连接所以出点和汇点,容量为1,费用为0
对于每条边(u,v,w),连接u,v+n,容量为1,费用为w;
费用流
#include <iostream> #include<cstdio> #include<string> #include<algorithm> #include<cstring> #include<queue> #define INF 0x7fffffff #define MAXN 405 #define MAXE 60805 using namespace std; int net[MAXN],size; struct Edge{ int v,next,cap,cost; }edge[MAXE]; void init(){ size=0; memset(net,-1,sizeof(net)); } void addedge(int u,int v,int cap,int cost){ //cout<<'*'<<u<<' '<<v<<' '<<cost<<endl; edge[size].v=v;edge[size].cap=cap;edge[size].cost=cost;edge[size].next=net[u];net[u]=size++; edge[size].v=u;edge[size].cap=0;edge[size].cost=-cost;edge[size].next=net[v];net[v]=size++; } int nv,dist[MAXN],pre[MAXN],pe[MAXN]; bool hash[MAXN]; queue<int> q; bool spfa(int s,int t){ while(!q.empty()) q.pop(); memset(hash,0,sizeof(hash)); memset(pre,-1,sizeof(pre)); for(int i=1;i<=nv;i++) dist[i]=INF; dist[s]=0; hash[s]=1; q.push(s); while(!q.empty()){ int u=q.front(); q.pop(); hash[u]=0; for(int i=net[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(edge[i].cap&&dist[v]>dist[u]+edge[i].cost){ dist[v]=dist[u]+edge[i].cost; pre[v]=u; pe[v]=i; if(hash[v]==0){ hash[v]=1; q.push(v); } } } } if(pre[t]==-1) return false; return true; } int MCMF(int s,int t,int need=0){ int max_flow=0; int min_cost=0; while(spfa(s,t)){ int aug=INF; for(int v=t;v!=s;v=pre[v]){ aug=min(aug,edge[pe[v]].cap); } max_flow+=aug; min_cost+=dist[t]*aug; for(int v=t;v!=s;v=pre[v]){ edge[pe[v]].cap-=aug; edge[pe[v]^1].cap+=aug; } } if(max_flow<need) return -1; return min_cost; } int main() { int T,s,t,u,v,w,i,ans,n,m; scanf("%d",&T); while(T--){ init(); scanf("%d%d",&n,&m); while(m--){ scanf("%d%d%d",&u,&v,&w); addedge(u,v+n,1,w); } s=0; t=n*2+1; for(i=1;i<=n;i++){ addedge(s,i,1,0); addedge(i+n,t,1,0); } nv=t+1; ans=MCMF(s,t,0); printf("%d\n",ans); } return 0; }
将值取反,求最大匹配,注意INF不能过大
#include <iostream> #include<cstdio> #include<string> #include<algorithm> #include<cstring> #include<queue> #define INF 60001 #define N 205 using namespace std; int nx,ny,lx ,ly ,link ,slack ,visx ,visy ,w ; bool DFS(int x){ int y; visx[x]=1; for(y=1;y<=ny;y++){ if(!visy[y]){ int t=lx[x]+ly[y]-w[x][y]; if(t==0){ visy[y]=1; if(link[y]==-1||DFS(link[y])){ link[y]=x; return true; } }else if(slack[y]>t){ slack[y]=t; } } } return false; } int KM(){ int i,j,x; memset(link,-1,sizeof(link)); memset(ly,0,sizeof(ly)); for(i=1;i<=nx;i++){ for(j=1,lx[i]=-INF;j<=ny;j++) if(w[i][j]>lx[i]) lx[i]=w[i][j]; } for(x=1;x<=nx;x++){ for(i=1;i<=ny;i++) slack[i]=INF; while(1){ memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(DFS(x)) break; int d=INF; for(i=1;i<=ny;i++) if(!visy[i]&&d>slack[i]) d=slack[i]; for(i=1;i<=nx;i++) if(visx[i]) lx[i]-=d; for(i=1;i<=ny;i++){ if(visy[i]) ly[i]+=d; else slack[i]-=d; } } } int ans=0; for(i=1;i<=ny;i++) if(link[i]>-1) ans+=w[link[i]][i]; return ans; } int main() { int T,s,t,i,j,k,ans,n,m; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); nx=ny=n; for(i=1;i<=n;i++){ for(j=1;j<=n;j++) w[i][j]=-INF; } while(m--){ scanf("%d%d%d",&i,&j,&k); w[i][j]=max(w[i][j],-k); } ans=KM(); printf("%d\n",-ans); } return 0; }
相关文章推荐
- 从零开始学OpenGLES开发——第五章
- 化解字符串不能超过8000的方法
- C#:ZedGraph画图控件(待补充)
- VI 命令 查找替换
- 第二十五题 求取字符串的排练组合输出
- Lucene suggest [转]
- mac安装配置JDK1.7
- Linux 安装流量监控软件bandwidthd
- printf格式控制符的完整格式
- 解决RedrawWindow()刷新界面出现闪烁的问题, VC对话框界面使用InvalidateRect刷新局部
- 懒省事的小明
- struts2中web.xml的配置
- 最火的.NET开源项目[转]
- MySQL5.6 基于db的并行复制
- 用asp.net 下载文件
- 域名解析和端口映射的结合,在任何网络环境发布网站、访问内网,原理分析与实际应用
- Generating Your Development Certificate
- <nine-patch> requires a valid 9-patch source image
- SpringAOP嵌套调用的解决办法
- iOS Crash Log 理解2