hdu 3488(KM算法||最小费用最大流)
Tour
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 2925 Accepted Submission(s): 1407
the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M
(M <= 30000) one-way roads connecting them. You are lucky enough to
have a chance to have a tour in the kingdom. The route should be
designed as: The route should contain one or more loops. (A loop is a
route like: A->B->……->P->A.)
Every city should be just in one route.
A
loop should have at least two cities. In one route, each city should be
visited just once. (The only exception is that the first and the last
city should be the same and this city is visited twice.)
The total distance the N roads you have chosen should be minimized.
In
each test case, the first line contains two integers N and M,
indicating the number of the cities and the one-way roads. Then M lines
followed, each line has three integers U, V and W (0 < W <=
10000), indicating that there is a road from U to V, with the distance
of W.
It is guaranteed that at least one valid arrangement of the tour is existed.
A blank line is followed after each test case.
6 9
1 2 5
2 3 5
3 1 10
3 4 12
4 1 8
4 6 11
5 4 7
5 6 9
6 5 4
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int INF = ;
const int N = ;
const int M = ;
struct Edge{
int u,v,cap,cost,next;
}edge[M];
int head[N],tot,low[N],pre[N];
int total ;
bool vis[N];
int flag[N][N];
void addEdge(int u,int v,int cap,int cost,int &k){
edge[k].u=u,edge[k].v=v,edge[k].cap = cap,edge[k].cost = cost,edge[k].next = head[u],head[u] = k++;
edge[k].u=v,edge[k].v=u,edge[k].cap = ,edge[k].cost = -cost,edge[k].next = head[v],head[v] = k++;
}
void init(){
memset(head,-,sizeof(head));
tot = ;
}
bool spfa(int s,int t,int n){
memset(vis,false,sizeof(vis));
for(int i=;i<=n;i++){
low[i] = (i==s)?:INF;
pre[i] = -;
}
queue<int> q;
q.push(s);
while(!q.empty()){
int u = q.front();
q.pop();
vis[u] = false;
for(int k=head[u];k!=-;k=edge[k].next){
int v = edge[k].v;
if(edge[k].cap>&&low[v]>low[u]+edge[k].cost){
low[v] = low[u] + edge[k].cost;
pre[v] = k; ///v为终点对应的边
if(!vis[v]){
vis[v] = true;
q.push(v);
}
}
}
}
if(pre[t]==-) return false;
return true;
}
int MCMF(int s,int t,int n){
int mincost = ,minflow,flow=;
while(spfa(s,t,n))
{
minflow=INF+;
for(int i=pre[t];i!=-;i=pre[edge[i].u])
minflow=min(minflow,edge[i].cap);
flow+=minflow;
for(int i=pre[t];i!=-;i=pre[edge[i].u])
{
edge[i].cap-=minflow;
edge[i^].cap+=minflow;
}
mincost+=low[t]*minflow;
}
total=flow;
return mincost;
}
int n,m;
int main(){
int tcase;
scanf("%d",&tcase);
while(tcase--){
init();
scanf("%d%d",&n,&m);
int src = ,des = *n+;
for(int i=;i<=n;i++){
addEdge(src,i,,,tot);
addEdge(i+n,des,,,tot);
}
memset(flag,-,sizeof(flag));
for(int i=;i<=m;i++){ ///去重
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if(flag[u][v]==-||w<flag[u][v]){
flag[u][v] = w;
}
}
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
if(flag[i][j]!=-){
addEdge(i,j+n,,flag[i][j],tot);
}
}
}
int mincost = MCMF(src,des,*n+);
if(total!=n) printf("-1\n");
else printf("%d\n",mincost);
}
}
题解二:KM算法,也是将一个点看成两个点,算最优匹配即可.
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int INF = ;
const int N = ;
int graph[N][N];
int lx[N],ly[N];
int linker[N];
bool x[N],y[N];
int n,m;
void init(){
memset(lx,,sizeof(lx));
memset(ly,,sizeof(ly));
memset(linker,-,sizeof(linker));
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
if(lx[i]<graph[i][j]) lx[i] = graph[i][j];
}
}
}
bool dfs(int u){
x[u] = true;
for(int i=;i<=n;i++){
if(!y[i]&&graph[u][i]==lx[u]+ly[i]){
y[i] = true;
if(linker[i]==-||dfs(linker[i])){
linker[i] = u;
return true;
}
}
}
return false;
}
int KM(){
int sum = ;
init();
for(int i=;i<=n;i++){
while(){
memset(x,false,sizeof(x));
memset(y,false,sizeof(y));
if(dfs(i)) break;
int d = INF;
for(int j=;j<=n;j++){
if(x[j]){
for(int k=;k<=n;k++){
if(!y[k]) d = min(d,lx[j]+ly[k]-graph[j][k]);
}
}
}
if(d==INF) break;
for(int j=;j<=n;j++){
if(x[j]) lx[j]-=d;
if(y[j]) ly[j]+=d;
}
}
}
for(int i=;i<=n;i++){
sum+=graph[linker[i]][i];
}
return sum;
}
int main()
{
int tcase;
scanf("%d",&tcase);
while(tcase--){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
graph[i][j] = -INF;
}
}
for(int i=;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
graph[u][v] = max(graph[u][v],-w);
}
int ans = KM();
printf("%d\n",-ans);
}
return ;
}
不去重之后还可以很快跑过去的某大牛的模板.
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<set>
#include<vector>
#include<map>
#include<queue>
#include<climits>
#include<assert.h>
#include<functional>
using namespace std;
const int maxn=;
const int INF=;
typedef pair<int,int> P; struct edge
{
int to,cap,cost,rev;
edge(int t,int c,int co,int r)
:to(t),cap(c),cost(co),rev(r){}
edge(){}
}; int V;//the number of points
vector<edge>G[maxn];
int h[maxn];
int dist[maxn];
int prevv[maxn],preve[maxn];
void add_edge(int from,int to,int cap,int cost)
{
G[from].push_back(edge(to,cap,cost,G[to].size()));
G[to].push_back(edge(from,,-cost,G[from].size()-));
} void clear()
{
for(int i=;i<V;i++) G[i].clear();
} int min_cost_flow(int s,int t,int f)
{
int res=,k=f;
fill(h,h+V,);//如果下标从1开始,就要+1
while(f>)
{
priority_queue<P,vector<P>,greater<P> >que;
fill(dist,dist+V,INF);
dist[s]=;
que.push(P(,s));
while(!que.empty())
{
P cur=que.top();que.pop();
int v=cur.second;
if(dist[v]<cur.first) continue;
for(int i=;i<G[v].size();i++)
{
edge &e=G[v][i];
if(e.cap>&&dist[e.to]>dist[v]+e.cost+h[v]-h[e.to])
{
dist[e.to]=dist[v]+e.cost+h[v]-h[e.to];
prevv[e.to]=v;
preve[e.to]=i;
que.push(P(dist[e.to],e.to));
}
}
}
if(dist[t]==INF)
{
return -;
}
for(int v=;v<V;v++) h[v]+=dist[v];//从0还是1开始需要结合题目下标从什么开始 int d=f;
for(int v=t;v!=s;v=prevv[v])
{
d=min(d,G[prevv[v]][preve[v]].cap);
}
f-=d;
res+=d*h[t];
for(int v=t;v!=s;v=prevv[v])
{
edge &e=G[prevv[v]][preve[v]];
e.cap-=d;
G[v][e.rev].cap+=d;
}
}
return res;
} int n,m;
int main(){
int tcase;
scanf("%d",&tcase);
while(tcase--){
scanf("%d%d",&n,&m);
clear();
V=*n+;
int src = ,des = *n+;
for(int i=;i<=n;i++){
add_edge(src,i,,);
add_edge(i+n,des,,);
}
for(int i=;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,n+v,,w);
}
int mincost = min_cost_flow(src,des,n);
printf("%d\n",mincost);
}
}
hdu 3488(KM算法||最小费用最大流)的更多相关文章
- hdu 3395(KM算法||最小费用最大流(第二种超级巧妙))
Special Fish Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tota ...
- 图论算法-最小费用最大流模板【EK;Dinic】
图论算法-最小费用最大流模板[EK;Dinic] EK模板 const int inf=1000000000; int n,m,s,t; struct node{int v,w,c;}; vector ...
- hdu 1533 Going Home 最小费用最大流
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1533 On a grid map there are n little men and n house ...
- HDU 5988.Coding Contest 最小费用最大流
Coding Contest Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)To ...
- hdu 3667(拆边+最小费用最大流)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3667 思路:由于花费的计算方法是a*x*x,因此必须拆边,使得最小费用流模板可用,即变成a*x的形式. ...
- HDU–5988-Coding Contest(最小费用最大流变形)
Coding Contest Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)To ...
- POJ 2195 & HDU 1533 Going Home(最小费用最大流)
这就是一道最小费用最大流问题 最大流就体现到每一个'm'都能找到一个'H',但是要在这个基础上面加一个费用,按照题意费用就是(横坐标之差的绝对值加上纵坐标之差的绝对值) 然后最小费用最大流模板就是再用 ...
- hdu 1533 Going Home 最小费用最大流 入门题
Going Home Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Tota ...
- hdoj 3488 Tour 【最小费用最大流】【KM算法】
Tour Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others) Total Submi ...
随机推荐
- HDU3068:最长回文(Manacher模板)
最长回文 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- DOM基本代码二
------------------------------- <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xh ...
- POJ 1661 DP
Help Jimmy Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 11071 Accepted: 3607 Descr ...
- python读书笔记-《简明python教程》上
1月15日 <简明python教程>上 基本结构: 基础概念+控制流+函数+模块+数据结构+面向对象+I/O+异常+标准库+其他 1.概念 1-0 退出python linux: ...
- java集合之深入分析ArrayList
ArrayList特点: ArrayList方法实现: 扩容方法的实现: 源码: private void ensureCapacityInternal(int minCapacity) { //如果 ...
- Activiti工作流——流程表数据转化
任务流程部署: 启动流程实例: 请假人完成请假申请: 部门经理完成审批: 总经理审批完成:
- 数据结构&字符串:可持久化字典树
利用可持久化Trie树实现范围内取值异或最大值 如果标题没有表达清楚意思,可以看这里的题干: 然后根据异或的性质,异或一个数两次相当于没有异或,那么我们可以维护一个异或前缀和 有了异或前缀和之后我们就 ...
- 【洛谷 P4934】 礼物 (位运算+DP)
题目链接 位运算+\(DP\)=状压\(DP\)?(雾 \(a\&b>=min(a,b)\)在集合的意义上就是\(a\subseteq b\) 所以对每个数的子集向子集连一条边,然后答案 ...
- 取(m堆)石子游戏 HDU2176(Nim博弈)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2176 题目: Problem Description m堆石子,两人轮流取.只能在1堆中取.取完者胜. ...
- Exponial (欧拉定理+指数循环定理+欧拉函数+快速幂)
题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=2021 Description Everybody loves big numbers ...