HDU 4411 Arrest 费用流

题目链接:点击打开链接

题意:

给定n+1个点([0,n] )m条边的无向图。起点为0,k个人初始在起点,

去遍历图使得每个点至少被一人走过且遍历 i 点时 i-1 必须已经被遍历。

使得k人的路径和最小,最后k人要回到起点。

思路:

费用流,因为对于一个人来说,这个人遍历点的序列一定是一个递增序列(不需要连续)

所以建图时i的出点只需要连接i+? 的入点。

若建一个完全图则会因为spfa跑负环。。。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<math.h>
using namespace std;
#define ll int
#define inf 1000000
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define N 250
#define M N*N*4
struct Edge {
	ll to, cap, cost, nex;
	Edge(){}
	Edge(ll to, ll cap, ll cost, ll next) :to(to), cap(cap), cost(cost), nex(next){}
} edge[M << 1];
ll head[N], edgenum;
ll D[N], A[N], P[N];
bool inq[N];
void add(ll from, ll to, ll cap, ll cost) {
	edge[edgenum] = Edge(to, cap, cost, head[from]);
	head[from] = edgenum++;
	edge[edgenum] = Edge(from, 0, -cost, head[to]);
	head[to] = edgenum++;
}
bool spfa(ll s, ll t, ll &flow, ll &cost) {
	for (ll i = 0; i <= t; i++) D[i] = inf;
	memset(inq, 0, sizeof inq);
	queue<ll>q;
	q.push(s);
	D[s] = 0; A[s] = inf;
	while (!q.empty()) {
		ll u = q.front(); q.pop();
		inq[u] = 0;
		for (ll i = head[u]; ~i; i = edge[i].nex)
		{
			Edge &e = edge[i];
			if (e.cap && D[e.to] > D[u] + e.cost)
			{
				D[e.to] = D[u] + e.cost;
				P[e.to] = i;
				A[e.to] = min(A[u], e.cap);
				if (!inq[e.to])
				{
					inq[e.to] = 1; q.push(e.to);
				}
			}
		}
	}
	//若费用为inf则中止费用流
	if (D[t] == inf) return false;
	cost += D[t] * A[t];
	flow += A[t];
	ll u = t;
	while (u != s) {
		edge[P[u]].cap -= A[t];
		edge[P[u] ^ 1].cap += A[t];
		u = edge[P[u] ^ 1].to;
	}
	return true;
}
ll Mincost(ll s, ll t){
	ll flow = 0, cost = 0;
	while (spfa(s, t, flow, cost));
	return cost;
}
void init(){ memset(head, -1, sizeof head); edgenum = 0; }
const int MAXN = 105;
int g[MAXN][MAXN];
int n, m, k;
void floyd() {
	for (int k = 0; k <= n; k++) {
		for (int i = 0; i <= n; i++) {
			for (int j = 0; j <= n; j++) {
				if (g[i][j] > g[i][k] + g[k][j]) {
					g[i][j] = g[i][k] + g[k][j];
				}
			}
		}
	}
}
int main(){
	while (scanf("%d%d%d", &n, &m, &k) != EOF) {
		if (n == 0 && m == 0 && k == 0) break;
		for (int i = 0; i <= n; i++){
			for (int j = 0; j <= n; j++)
				g[i][j] = 10000005;
			g[i][i] = 0;
		}
		for (int i = 0, u, v, w; i < m; i++) {
			scanf("%d%d%d", &u, &v, &w);
			g[u][v] = g[v][u] = min(w, g[u][v]);
		}
		floyd();
		init();
		int to = n * 2 + 3, from = n * 2 + 2;
		for (int i = 1; i <= n; i++){
			add(0, i * 2, 1, g[0][i]);
			add(i * 2, i * 2 + 1, 1, -inf);
			add(i * 2 + 1, to, 1, g[i][0]);
			for (int j = i + 1; j <= n; j++)
				add(i * 2 + 1, j * 2, 1, g[i][j]);
		}
		add(from, 0, k, 0);
		add(0, to, k, 0);
		printf("%d\n", Mincost(from, to) + inf*n);
	}
	return 0;
}	
时间: 2024-10-06 06:10:50

HDU 4411 Arrest 费用流的相关文章

HDU 4862 Jump 费用流

又是一个看了题解以后还坑了一天的题…… 结果最后发现是抄代码的时候少写了一个负号. 题意: 有一个n*m的网格,其中每个格子上都有0~9的数字.现在你可以玩K次游戏. 一次游戏是这样定义的: 你可以选任意之前没有走过的格子作为起点.然后走任意步,其中每一步你可以向右或者向下走任意格.假如从(x1, y1)走到(x2, y2)需要花费能量|x1-x2|+|y1-y2|-1,如果这一步和上一步格子的数字相同,那么可以获得格子上相应数字的能量.能量可以为负值. 问你,在K次以内走完所以格子最多能得到多

POJ 3422 HDU 2686,3376 费用流拆点建图

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3376 http://acm.hdu.edu.cn/showproblem.php?pid=2686 http://poj.org/problem?id=3422 POJ 3422为从矩阵左上角走到右下角,最多走k次,每个格子里的数字只能算一次,后面可以重复经过,求经过的各个数字的和的最大值. 拆点,入点向出点连流量为1,费用为当前格子负值的边,向下方,右方连边,流量为k,费用为0,起点连流量为1,

hdu 2853 Assignment 费用流

就是本来就给出了一个匹配,然后让你求一个权值最大的匹配,并且和初始匹配变动最小. #include <stdio.h> #include <iostream> #include <string.h> using namespace std; const int N=400; const int MAXE=20000000; const int inf=1<<30; int head[N],s,t,cnt,ans; int d[N],pre[N]; bool

HDU 4411 Arrest

http://www.cnblogs.com/jianglangcaijin/archive/2012/09/24/2700509.html 思路: S->0 流量为K费用0 0->i 流量为inf,费用为a[0][i] 0->T 流量为K,费用0 i->i+n 流量为1,费用为-inf i+n->T 流量为1,费用为a[0][i] 1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath

Going Home HDU - 1533 (费用流)

Going Home HDU - 1533 1 //费用流初探 2 #include <iostream> 3 #include <queue> 4 #include <cstring> 5 #include <cstdio> 6 #include <algorithm> 7 using namespace std; 8 const int inf = 0x3f3f3f3f; 9 const int maxn = 110; 10 char gra

POJ 2135 Farm Tour &amp;&amp; HDU 2686 Matrix &amp;&amp; HDU 3376 Matrix Again 费用流求来回最短路

累了就要写题解,最近总是被虐到没脾气. 来回最短路问题貌似也可以用DP来搞,不过拿费用流还是很方便的. 可以转化成求满流为2 的最小花费.一般做法为拆点,对于 i 拆为2*i 和 2*i+1,然后连一条流量为1(花费根据题意来定) 的边来控制每个点只能通过一次. 额外添加source和sink来控制满流为2. 代码都雷同,以HDU3376为例. #include <algorithm> #include <iostream> #include <cstring> #in

hdu 4862 Jump 上下界费用流

对于每个点拆点成为两个点a,b,连接a到b的上界为1,下界为1的边,保证用过一次且仅一次. 然后若点u可到达点v,则连接即可.建成了一个上下界网络,将下界拆出去,求最大费用最大流就好. #include <stdio.h> #include <iostream> #include <string.h> using namespace std; const int N=800; const int MAXE=200000; const int inf=1<<3

HDU 4406 GPA(网络流-最大费用流)

GPA Problem Description GPA(Grade-Point Average) is one way to measure students' academic performance in PKU. Each course has an integer credit, ranges from 1 to 99. For each course, you will get a score at the end of the semester, which is an intege

HDU 4862 Jump 最小k路径覆盖 费用流

gg... 题意: 给定n*m的矩阵 选<=k个起点 每个起点可以向右或向下跳任意步 花费是2点间的曼哈顿距离 若2个格子的数字一样 则赚取格子上的数字的价值 问:遍历整个图的最小花费 若不能遍历则输出-1 #include <stdio.h> #include <string.h> #include <iostream> #include <math.h> #include <queue> #include <set> #in