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, ...
随机推荐
- HTML 14 JS事件
一 :什么是事件 发生的某一件事:触发特定的条件,完成某一项功能 二:学习的目的 在特定的条件下,完成特定的功能 条件满足的情况下,系统会自动执行 ( 回调 ) 绑定的方法 学习要点: 1.事件的两种 ...
- Python 35 线程(1)线程理论、开启线程的两种方式
一:线程理论 1 什么是线程 进程其实一个资源单位,而进程内的线程才是cpu上的执行单位 线程其实指的就是代码的执行过程2 为何要用线程 线程vs进程 1. 同一进程下的多个线程共享该进程 ...
- java常见面试题03-String,StringBuffer,StringBuilder的区别
面试题 A:String,StringBuffer,StringBuilder的区别 1:String 内容不可变,StringBuffer.StringBudiler可变 2:StringBu ...
- sql 改字段名
sp_rename '[zErpMini].[dbo].[STK_Stock].Isextension','IsExtened'
- Redis 字符串结构和常用命令
字符串是 Redis 最基本的数据结构,它将以一个键 和一个值 储存在 Redis 内部. 字符串的一些基本命令 命令 说明 备注 set key value 设置键值对 最常用的写入命令 get k ...
- Deutsch lernen (11)
1. anwesend a. 出席的,在场的 ~ abwesend Es waren gegen 50 Leute anwesend. 2. gespannt a. (心情)急切的,急于想知道的:紧张 ...
- Percona Xtrabackup对数据库进行部分备份
Xtrabackup也可以实现部分备份,即只备份某个或某些指定的数据库或某数据库中的某个或某些表.但要使用此功能,必须启用innodb_file_per_table选项,即每张表保存为一个独立的文件. ...
- QT显示框架嵌入Vs控制台工程
一.一些准备工作: 1.安装Qt for VS 的插件: 安装Qt for VS 的插件 下载地址:http://download.qt.io/official_releases/vsaddin/ ...
- 阿里巴巴矢量库IconFont__使用小录
使用阿里巴巴矢量库方法虽然不难,但本人记性不好,遂在次记录几笔 阿里巴巴矢量库地址:http://www.iconfont.cn/plus 阿里巴巴矢量库图标好处: 1:图标矢量化 2:自己总结:ic ...
- OAuth四种模式
授权码模式(authorization code)----适用于网站服务端去oauth服务端申请授权 简化模式(implicit)----没有服务端,js+html页面去oauth服务端申请授权 密码 ...