Tour

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 2925    Accepted Submission(s): 1407

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
1
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
 
Sample Output
42
 
题意:和hdu 1853题意和解法几乎一样,但是这题我看英文硬是没看懂。。。题意就是n个城市,每个城市都必须在一个环里面并且也只能出现在一个环里面?问最小的花费是多少?
题解:解法一:最小费用最大流:要去重 不然TLE。每个点只能出现一次,那么一个点容量限制为1,然后拆点跑最小费用最大流即可.
#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算法||最小费用最大流)的更多相关文章

  1. hdu 3395(KM算法||最小费用最大流(第二种超级巧妙))

    Special Fish Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tota ...

  2. 图论算法-最小费用最大流模板【EK;Dinic】

    图论算法-最小费用最大流模板[EK;Dinic] EK模板 const int inf=1000000000; int n,m,s,t; struct node{int v,w,c;}; vector ...

  3. 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 ...

  4. HDU 5988.Coding Contest 最小费用最大流

    Coding Contest Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)To ...

  5. hdu 3667(拆边+最小费用最大流)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3667 思路:由于花费的计算方法是a*x*x,因此必须拆边,使得最小费用流模板可用,即变成a*x的形式. ...

  6. HDU–5988-Coding Contest(最小费用最大流变形)

    Coding Contest Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)To ...

  7. POJ 2195 & HDU 1533 Going Home(最小费用最大流)

    这就是一道最小费用最大流问题 最大流就体现到每一个'm'都能找到一个'H',但是要在这个基础上面加一个费用,按照题意费用就是(横坐标之差的绝对值加上纵坐标之差的绝对值) 然后最小费用最大流模板就是再用 ...

  8. hdu 1533 Going Home 最小费用最大流 入门题

    Going Home Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Tota ...

  9. hdoj 3488 Tour 【最小费用最大流】【KM算法】

    Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submi ...

随机推荐

  1. 第六章 指针与const

    const一词在字面上来源于常量constant,const对象在C/C++中是有不同解析的,如第二章所述,在C中常量表达式必须是编译期,运行期的不是常量表达式,因此C中的const不是常量表达式:但 ...

  2. ubuntu16.04装chrome

    --更简单的方法是先下载chromium浏览器,这是不禁止的,然后打开chromium搜索chrome,chrome的官网下载即可   //安装好后,终端输入google-chrome即可打开 另一种 ...

  3. oepncv-学习笔记一

    安装opencv文件时若需要cmake编译,如果中间出现 解决办法是: 在opencv的文件中找到包含cmakelist.txt的文件夹,把where is the source code:的路径改成 ...

  4. 前端为什么要对url进行编码

    为什么要对url进行编码 url有规范,在参数值中出现&字符会截断参数 url中文的问题,编码客转换为英文 也是第一种情况,url中有个参数值是url,传输的时候会出现错误 例1 有这样一串参 ...

  5. 南阳ACM 题目22:素数求和问题

    素数求和问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:2 描述 现在给你N个数(0<N<1000),现在要求你写出一个程序,找出这N个数中的所有素数,并求和. ...

  6. ? 初识Webx 3

    初识webx 2: http://www.cnblogs.com/lddbupt/p/5552351.html Webx Turbine建立在Webx Framework的基础上,实现了页面渲染.布局 ...

  7. intellj idea点击导航栏打开的一个类,怎么才能定位到类的目录

  8. 省队集训 Day7 选点游戏

    [题目大意] 维护一个$n$个点的图,$m$个操作,支持两个操作: 1. 连接$(u, v)$这条边: 2. 询问$u$所在的联通块中,能选出的最大合法的点数. 一个方案是合法的,当且仅当对于所有被选 ...

  9. Solaris 选择使用不同网口的操作

    机器上集成两个物理网口,由于先前使用的网口传输速率特别慢且容易丢包,故换成另一个网口,操作如下: 1.查看物理设备信息-- 显示可用的数据链路 root@238-spa:~# dladm show-p ...

  10. linux系统环境 ——(四)

    默认有6个命令交互通道和一个图形界面交互通道,默认进入到的是图形界面通道 命令交互模式切换:ctrl+alt+f1---f6 图形交互界面 ctrl+alt+f7 1.图形界面交互模式 - termi ...