hdoj 3488 Tour 【最小费用最大流】【KM算法】
TourTime Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)
Problem Description
In 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.
Input
An integer T in the first line indicates the number of the test cases.
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.
Output
For each test case, output a line with exactly one integer, which is the minimum total distance.
Sample Input
Sample Output
|
用费用流G++能够卡过,C++会超时。
用KM应该非常快吧,如今先刷费用流,过几天再好好做KM。
题意:给出n个点m条单向边边以及经过每条边的费用,让你求出走过一个哈密顿环(除起点外,每一个点仅仅能走一次)的最小费用。题目保证至少存在一个环满足条件,事实上推断成环仅仅须要推断是否满流就可以。
思路: 把每一个点i拆分成左点i和右点i+N
1。超级源点连左点。容量为1,费用为0
2。全部右点连超级汇点,容量为1。费用为0
3,每条单向边—— 起点左点 连 终点右点 容量为1,费用为边权。
最后跑一下费用流即可了。
注意重边的处理,不去重费用流会超时,还有要用G++提交。 抽出时间再补上KM的AC代码。
费用流AC代码:
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#define MAXN 400+10
#define MAXM 70000+10
#define INF 0x3f3f3f3f
using namespace std;
struct Edge
{
int from, to, cap, flow, cost, next;
};
Edge edge[MAXM];
int head[MAXN], edgenum;
int pre[MAXN], dist[MAXN];
bool vis[MAXN];
int N, M;
int source, sink;
void init()
{
edgenum = 0;
memset(head, -1, sizeof(head));
}
void addEdge(int u, int v, int w, int c)//必须去重!!! {
int i;
for(i = head[u]; i != -1; i = edge[i].next)
{
if(edge[i].to == v)
break;
}
if(i != -1)
{
if(edge[i].cost > c)
edge[i].cost = c, edge[i^1].cost = -c;
return ;
}
Edge E1 = {u, v, w, 0, c, head[u]};
edge[edgenum] = E1;
head[u] = edgenum++;
Edge E2 = {v, u, 0, 0, -c, head[v]};
edge[edgenum] = E2;
head[v] = edgenum++;
}
void getMap()
{
scanf("%d%d", &N, &M);
int a, b, c;
source = 0, sink = 2 * N + 1;
//把每一个点i拆分成左点i和右点i+N
//超级源点连左点。容量为1,费用为0
//全部右点连超级汇点。容量为1,费用为0
//单向边: 起点左点连终点右点 容量为1,费用为边权
for(int i = 1; i <= N; i++)
addEdge(source, i, 1, 0),
//addEdge(i, i + N, 1, 0),
addEdge(i + N, sink, 1, 0);
while(M--)
{
scanf("%d%d%d", &a, &b, &c);
addEdge(a, b+N, 1, c);
}
}
bool SPFA(int s, int t)
{
queue<int> Q;
memset(dist, INF, sizeof(dist));
memset(vis, false, sizeof(vis));
memset(pre, -1, sizeof(pre));
dist[s] = 0;
vis[s] = true;
Q.push(s);
while(!Q.empty())
{
int u = Q.front();
Q.pop();
vis[u] = false;
for(int i = head[u]; i != -1; i = edge[i].next)
{
Edge E = edge[i];
if(dist[E.to] > dist[u] + E.cost && E.cap > E.flow)
{
dist[E.to] = dist[u] + E.cost;
pre[E.to] = i;
if(!vis[E.to])
{
vis[E.to] = true;
Q.push(E.to);
}
}
}
}
return pre[t] != -1;
}
void MCMF(int s, int t, int &cost, int &flow)
{
flow = cost = 0;
while(SPFA(s, t))
{
int Min = INF;
for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
{
Edge E = edge[i];
Min = min(Min, E.cap - E.flow);
}
for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
{
edge[i].flow += Min;
edge[i^1].flow -= Min;
cost += edge[i].cost * Min;
}
flow += Min;
}
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
init();
getMap();
int cost, flow;
MCMF(source, sink, cost, flow);
printf("%d\n", cost);
}
return 0;
}
KM算法:重刷
边权取负。注意重边的处理。
AC代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
#define MAXN 210
using namespace std;
int lx[MAXN], ly[MAXN];
int Map[MAXN][MAXN];
bool visx[MAXN], visy[MAXN];
int slack[MAXN];
int match[MAXN];
int N, M;
void getMap()
{
for(int i = 1; i <= N; i++)
{
for(int j = 1; j <= N; j++)
Map[i][j] = -INF;
}
int a, b, c;
while(M--)
{
scanf("%d%d%d", &a, &b, &c);
if(-c > Map[a][b])
Map[a][b] = -c;
}
}
int DFS(int x)
{
visx[x] = true;
for(int y = 1; y <= N; y++)
{
if(visy[y]) continue;
int t = lx[x] + ly[y] - Map[x][y];
if(t == 0)
{
visy[y] = true;
if(match[y] == -1 || DFS(match[y]))
{
match[y] = x;
return 1;
}
}
else if(slack[y] > t)
slack[y] = t;
}
return 0;
}
void KM()
{
memset(match, -1, sizeof(match));
memset(ly, 0, sizeof(ly));
for(int x = 1; x <= N; x++)
{
lx[x] = -INF;
for(int y = 1; y <= N; y++)
lx[x] = max(lx[x], Map[x][y]);
}
for(int x = 1; x <= N; x++)
{
for(int i = 1; i <= N; i++)
slack[i] = INF;
while(1)
{
memset(visx, false, sizeof(visx));
memset(visy, false, sizeof(visy));
if(DFS(x)) break;
int d = INF;
for(int i = 1; i <= N; i++)
{
if(!visy[i] && slack[i] < d)
d = slack[i];
}
for(int i = 1; i <= N; i++)
{
if(visx[i])
lx[i] -= d;
}
for(int i = 1; i <= N; i++)
{
if(visy[i])
ly[i] += d;
else
slack[i] -= d;
}
}
}
int ans = 0;
for(int i = 1; i <= N; i++)
ans += Map[match[i]][i];
printf("%d\n", -ans);
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &N, &M);
getMap();
KM();
}
return 0;
}
hdoj 3488 Tour 【最小费用最大流】【KM算法】的更多相关文章
- TZOJ 1513 Farm Tour(最小费用最大流)
描述 When FJ's friends visit him on the farm, he likes to show them around. His farm comprises N (1 &l ...
- Farm Tour(最小费用最大流模板)
Farm Tour Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 18150 Accepted: 7023 Descri ...
- POJ2135 Farm Tour —— 最小费用最大流
题目链接:http://poj.org/problem?id=2135 Farm Tour Time Limit: 1000MS Memory Limit: 65536K Total Submis ...
- poj 2351 Farm Tour (最小费用最大流)
Farm Tour Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 17230 Accepted: 6647 Descri ...
- poj 2135 Farm Tour 最小费用最大流建图跑最短路
题目链接 题意:无向图有N(N <= 1000)个节点,M(M <= 10000)条边:从节点1走到节点N再从N走回来,图中不能走同一条边,且图中可能出现重边,问最短距离之和为多少? 思路 ...
- POJ 2135 Farm Tour [最小费用最大流]
题意: 有n个点和m条边,让你从1出发到n再从n回到1,不要求所有点都要经过,但是每条边只能走一次.边是无向边. 问最短的行走距离多少. 一开始看这题还没搞费用流,后来搞了搞再回来看,想了想建图不是很 ...
- hdu 1853 Cyclic Tour 最小费用最大流
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1853 There are N cities in our country, and M one-way ...
- [poj] 1235 Farm Tour || 最小费用最大流
原题 费用流板子题. 费用流与最大流的区别就是把bfs改为spfa,dfs时把按deep搜索改成按最短路搜索即可 #include<cstdio> #include<queue> ...
- POJ-2516(最小费用最大流+MCMF算法)
Minimum Cost POJ-2516 题意就是有n个商家,有m个供货商,然后有k种商品,题目求的是满足商家的最小花费供货方式. 对于每个种类的商品k,建立一个超级源点和一个超级汇点.每个商家和源 ...
- POJ-2195(最小费用最大流+MCMF算法)
Going Home POJ-2195 这题使用的是最小费用流的模板. 建模的时候我的方法出现错误,导致出现WA,根据网上的建图方法没错. 这里的建图方法是每次到相邻点的最大容量为INF,而花费为1, ...
随机推荐
- Spring的AOP机制---- AOP的注解配置---- AOP的注解配置
3333隐隐约约隐隐约约隐隐约约隐隐约约隐隐约约隐隐约约隐隐约约隐隐约约隐隐约约隐隐约约隐隐约约隐隐约约隐隐约约隐隐约约隐隐约约隐隐约约噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢 ...
- [hihocoder][Offer收割]编程练习赛50
循环数组 计算a[i]的前缀和s[i],计算l[i]为1~i-1中最小的s值,r[i]为i~n中最大的s值. 则a[i]~a[n]满足性质的条件为r[i]-s[i-1]>0,a[1]~a[i-1 ...
- 【转载】JavaScript中同名标识符优先级-Snandy
一,局部变量先使用后声明,不影响外部同名变量 var x = 1; // --> 外部变量x function fn(){ alert(x); // --> undefined 局部变量x ...
- Beta冲刺-星期四
这个作业属于哪个课程 <课程的链接> 这个作业要求在哪里 <作业要求的链接> 团队名称 Three cobblers 这个作业的目标 完成今天的冲刺 一 ...
- dubbo之服务分组
当一个接口有多种实现时,可以用group区分. 服务 <dubbo:service group="feedback" interface="com.xxx.Inde ...
- (1)dotnet开源电商系统-brnshop&brnMall 和老外开发的nopCommerce(dotnet两套电商来PK--第一篇)
一直想做电商软件,但是实在不想学PHP了,所以前后关注了这两个开源电商系统.一个是国人出品的,一个据说是俄罗斯人写得(不知道对不对).目前两个开源软件都在学习了解中,以下的博文可能会涉及到这两套系统, ...
- Tomcat Eclipse Debug出现异常
1.可能是java类没有及时更新成class文件2.本地程序没有同步到Tommcat服务器里面3.Servlet类里面加了版本号private static final long serialVers ...
- webpack command not found 的意外的坑 - 原因是从node开始
写给自己做个记录: 弄了半天 执行了下面操作 npm install webpack -g 因为小白不懂原理,所以执行了好遍,结果还是如题, webpack command not found 网上搜 ...
- 【剑指Offer】33、丑数
题目描述: 把只包含质因子2.3和5的数称作丑数(Ugly Number).例如6.8都是丑数,但14不是,因为它包含质因子7. 习惯上我们把1当做是第一个丑数.求按从小到大的顺序的第N个丑数 ...
- 阿里云服务器centos7环境下安装xampp后,mysql有进程,但是却没有监听3306端口
配置阿里云服务器centos7中xampp环境时出现了一种情况: 在centos中可以使用命令进入mysql 修改后也可以远程用phpmyadmin连接mysql 但是用navicat却无法连接 先修 ...