HDU 3523 最小费用流或KM
来源:互联网 发布:三生网络直销平台 编辑:程序博客网 时间:2024/06/11 09:51
点击打开链接
题意:这题的题意隐晦的可以,中间不说了直接说求什么,求的是你画一张照片,照片有n个元素,1到n每个出现一次,问你对于上面的m张照片,如何分配你画的1到n使得题目中的式子的值最小,解释第二组样例应该就行了我们画的照片就可以是1 4 2 5 7 9 3 8 6没错就是第一行元素,那么对于第一列来说值是9,第二列的值是7,到第9列分别为9 7 7 1 4 11 4 8 7,那么最后值为58,求得就是这个最小的值
思路:对于每一列我可以选择的是1到n,那么就可以分别处理出1到n的话这个差值,然后我们不难发现这就是最小费用流,也可以理解为最小权匹配,所以看了大家的做法都是KM,我写的费用流都一样,建图的话应该很好建,模型还是挺简单的,看代码应该就可以看懂
#include <queue>#include <vector>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <iostream>#include <algorithm>#include <functional>using namespace std;typedef long long ll;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const ll INF=0x3f3f3f3f3f3f3f3fll;const int maxn=2010;typedef pair<int,int> P;struct edge{ int to,cap,rev,cost; edge(); edge(int a,int b,int c,int d){to=a,cap=b,cost=c,rev=d;};};vector<edge>G[maxn];int h[maxn],dis[maxn];int prevv[maxn],preve[maxn];void add_edge(int st,int en,int cap,int cost){ G[st].push_back(edge(en,cap,cost,G[en].size())); G[en].push_back(edge(st,0,-cost,G[st].size()-1));}int min_cost_flow(int st,int en,int f){ int ans=0; memset(h,0,sizeof(h)); while(f>0){ priority_queue<P,vector<P>,greater<P> >que; for(int i=0;i<maxn;i++) dis[i]=inf; dis[st]=0;que.push(P(0,st)); while(!que.empty()){ P p=que.top();que.pop(); int v=p.second; if(dis[v]<p.first) continue; for(unsigned int i=0;i<G[v].size();i++){ edge &e=G[v][i]; if(e.cap>0&&dis[e.to]>dis[v]+e.cost+h[v]-h[e.to]){ dis[e.to]=dis[v]+e.cost+h[v]-h[e.to]; prevv[e.to]=v; preve[e.to]=i; que.push(P(dis[e.to],e.to)); } } } if(dis[en]==inf) return -1; for(int i=0;i<maxn;i++) h[i]+=dis[i]; int d=f; for(int i=en;i!=st;i=prevv[i]){ d=min(d,G[prevv[i]][preve[i]].cap); } f-=d; ans+=d*h[en]; for(int i=en;i!=st;i=prevv[i]){ edge &e=G[prevv[i]][preve[i]]; e.cap-=d; G[i][e.rev].cap+=d; } } return ans;}int num[110][110],tmp[110][110];int main(){ int T,n,m,cas=1; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); for(int i=0;i<maxn;i++) G[i].clear(); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) scanf("%d",&num[i][j]); for(int i=1;i<=n;i++) add_edge(0,i,1,0); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ int sum=0; for(int k=1;k<=m;k++) sum+=abs(num[k][j]-i); tmp[j][i]=sum; } } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ add_edge(i,n+j,1,tmp[j][i]); } } for(int i=1;i<=n;i++) add_edge(n+i,2*n+1,1,0); int ans=min_cost_flow(0,2*n+1,n); printf("Case #%d: %d\n",cas++,ans); } return 0;}KM的话也是直接模版,权值变负求最大权,然后结果再变正就行了 PS:这道题目的难点好像是读懂题目把~~~~
#include <stdio.h>#include <string.h>#include <stdlib.h>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const ll INF=0x3f3f3f3f3f3f3f3fll;const int maxn=210;int s[maxn][maxn],visx[maxn],visy[maxn],match[maxn],num[maxn][maxn];int lx[maxn],ly[maxn],tmp[maxn][maxn];int n,m;int hungarian(int x){ visx[x]=1; for(int i=1;i<=m;i++){ if(!visy[i]&&lx[x]+ly[i]==s[x][i]){ visy[i]=1; if(!match[i]||hungarian(match[i])){ match[i]=x; return 1; } } } return 0;}int KM(){ int sum=0; memset(lx,0,sizeof(lx)); memset(ly,0,sizeof(ly)); memset(match,0,sizeof(match)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) lx[i]=max(lx[i],s[i][j]); for(int i=1;i<=n;i++){ while(1){ memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(hungarian(i))break; else{ int temp=INF; for(int j=1;j<=n;j++){ if(visx[j]){ for(int k=1;k<=m;k++) if(!visy[k]) temp=min(temp,lx[j]+ly[k]-s[j][k]); } } if(temp==INF) return -1; for(int j=1;j<=n;j++) if(visx[j]) lx[j]-=temp; for(int j=1;j<=m;j++) if(visy[j]) ly[j]+=temp; } } } for(int i=1;i<=m;i++){ if(match[i]!=0){ if(s[match[i]][i]!=-INF) sum+=s[match[i]][i]; else return -1; } } return sum;}int main(){ int T,cas=1,n1,m1; scanf("%d",&T); while(T--){ scanf("%d%d",&n1,&m1); n=m=n1; for(int i=1;i<=m1;i++) for(int j=1;j<=n1;j++) scanf("%d",&num[i][j]); for(int i=1;i<=n1;i++){ for(int j=1;j<=n1;j++){ int sum=0; for(int k=1;k<=m1;k++) sum+=abs(num[k][j]-i); tmp[j][i]=sum; } } for(int i=1;i<=n1;i++){ for(int j=1;j<=n1;j++){ s[i][j]=-tmp[j][i]; } } int ans=KM(); printf("Case #%d: %d\n",cas++,-ans); } return 0;}
0 0
- HDU 3523 最小费用流或KM
- HDU 3488 Tour (最小费用流 或 KM)
- hdu 4862KM&最小费用最大流
- HDU 3488 Tour [裂点+KM或最小费用最大流]
- POJ--3686[The Windy's] 最小费用流或KM
- poj 2516 Minimum Cost KM或最小费用流
- HDU 1533 Going Home【最小费用流|KM算法】
- HDU 3435 KM算法或者最小费用最大流
- POJ_3686_The Windy's(最小费用流 / KM)
- HDU 2426 Interesting Housing Problem 最小费用最大流 or KM算法
- HDU 2426 Interesting Housing Problem 二分匹配(KM模板)或者最小费用最大流
- HDU-1533 KM Going Home 最佳匹配 最小费用最大流
- HDU 2448 Mining Station on the Sea(最小费用最大流, KM算法)
- HDU 4494 Teamwork(最大流或最小费用流)
- hdu 2686 Matrix - 最小费用最大流 或 多线程DP
- HDU 1533Going Home(KM算法求二分图最小权匹配或者最小费用最大流)
- POJ 2516 Minimum Cost (最小费用最大流,KM解法)
- hdu1853 Cyclic Tour (KM算法求最小费用流)
- 各种滤波算法的比较
- MapReduce从HBase多路径导出数据到Hive
- 【Android】在任何View上添加红点★★★★★★★
- Android Fragment 真正的完全解析(上)
- execel导出和下载
- HDU 3523 最小费用流或KM
- BOS项目练习(流程定义/实例管理,bos用户角色同步activiti用户表组表)
- dumpbin丢失mspdb 问题
- 第十六周--阅读程序
- 给TextView设置图片的两种实现方法
- UVa 11300 Spreading the Wealth (线性方程组约束下的最优化问题)
- android权限相关的知识
- 数据库连接池
- Sqlite 导出表结构和数据