Uva 11146 Insurrection(最短路+最小割)

题目地址:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2087

思路:

1.删除k个点使得点1到点n不连通。

2.拆点。将每个点拆为i和i’,容量为删除该点的花费(即为从1点到该点的最短路+n点到该点的最短路)。

3.对于原图中的无向边i-j,连边i'->j,j'->i,容量均为正无穷。则答案即为点1到点n的最大流(即最小割)。

4.当最大流大于等于INF时,无解。也即为点1和点n直接有边相连。

#include
#include
#include
#include
#include
#include
#include
#define debug
using namespace std;

const double eps = 1e-6;
const int maxn = 2000 + 50;
const int maxm = 2000 + 50;
const int INF = 0x3f3f3f3f;

struct Edge
{
	int from, to;
	double cap, flow;
	Edge(int a, int b, double c, double d) :from(a), to(b), cap(c), flow(d) {}
};

int dcmp(double x)
{
	if (fabs(x) < eps) return 0;
	else return x < 0 ? -1 : 1;
}

struct Dinic
{
	int n, m, s, t;
	vector edges;
	vector G[maxn];
	bool vis[maxn];
	int d[maxn];
	int cur[maxn];
	void init(int n)
	{
		this->n = n;
		for (int i = 0; i <= n; i++) G[i].clear();
		edges.clear();
	}
	void addEdge(int from, int to, double cap)
	{
		edges.push_back(Edge(from, to, cap, 0));
		edges.push_back(Edge(to, from, 0, 0));
		m = edges.size();
		G[from].push_back(m - 2);
		G[to].push_back(m - 1);
	}
	bool BFS()
	{
		memset(vis, 0, sizeof(vis));
		queue Q;
		Q.push(s);
		vis[s] = 1;
		d[s] = 0;
		while (!Q.empty())
		{
			int x = Q.front();
			Q.pop();
			for (int i = 0; i < G[x].size(); i++)
			{
				Edge& e = edges[G[x][i]];
				if (!vis[e.to] && dcmp(e.cap - e.flow)>0)
				{
					vis[e.to] = 1;
					d[e.to] = d[x] + 1;
					Q.push(e.to);
				}
			}
		}
		return vis[t];
	}
	double DFS(int x, double a)
	{
		if (x == t || dcmp(a) == 0) return a;
		double flow = 0, f;
		for (int& i = cur[x]; i < G[x].size(); i++)
		{
			Edge& e = edges[G[x][i]];
			if (d[x] + 1 == d[e.to] && (dcmp(f = DFS(e.to, min(a, e.cap - e.flow)))) > 0)
			{
				e.flow += f;
				edges[G[x][i] ^ 1].flow -= f;
				flow += f;
				a -= f;
				if (dcmp(a) == 0) break;
			}
		}
		return flow;
	}
	double MaxFlow(int s, int t)
	{
		this->s = s;
		this->t = t;
		double flow = 0;
		while (BFS())
		{
			memset(cur, 0, sizeof(cur));
			flow += DFS(s, INF);
		}
		return flow;
	}
};


struct E
{
	int nt, to;
};

Dinic g;
queue q;
E edge[maxm];
int head[maxn];
int n, m, S, T;
double w[maxn];
int vis[maxn], tot;
double dist[2][maxn];

void addEdge(int u, int v)
{
	edge[tot].to = v, edge[tot].nt = head[u],head[u] = tot++;
}

void mindist(int s, int id)
{
	while (!q.empty()) q.pop();
	memset(vis, 0, sizeof(vis));
	for (int i = 0; i <= n; i++) dist[id][i] = INF;
	q.push(s), vis[s] = 1, dist[id][s] = 0;
	while (!q.empty())
	{
		int now = q.front();
		q.pop(), vis[now] = 0;
		for (int i = head[now]; ~i; i = edge[i].nt)
		{
			int nt = edge[i].to;
			if (dcmp(dist[id][nt] -(dist[id][now] + w[nt]))>0)
			{
				dist[id][nt] = dist[id][now] + w[nt];
				if (!vis[nt])
				{
					vis[nt] = 1;
					q.push(nt);
				}
			}
		}
	}
}

void init()
{
	tot = 0;
	memset(w, 0, sizeof(w));
	memset(head, -1, sizeof(head));
	g.init(2*n + 1);
}

int main()
{
#ifdef  debu
	freopen("in.txt", "r", stdin);
#endif //  debug 

	int t;
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d%d", &n, &m);
		init();
		for (int i = 2; i <= n - 1; i++)
		{
			scanf("%lf", &w[i]);
		}
		for (int i = 0; i < m; i++)
		{
			int x, y;
			scanf("%d%d", &x, &y);
			addEdge(x, y);
			addEdge(y, x);
		}

		mindist(1, 0);
		mindist(n, 1);
		
		S = 1, T =n;

		for (int i = 1; i <= n; i++)
		{
			if (i != 1 && i != n)
			{
				g.addEdge(i, i + n, dist[0][i] + dist[1][i]);
			}
			for (int j = head[i]; ~j; j = edge[j].nt)
			{
				int nt = edge[j].to;
				if (i != 1 && i != n)
				{
					g.addEdge(i + n, nt, INF);
				}
				else
				{
					g.addEdge(i, nt, INF);
				}
			}
		}

		double ans = g.MaxFlow(S, T);
		if(ans>=INF)printf("No Solution!\n");
		else printf("%.4f\n", ans);
	}
	return 0;
}





你可能感兴趣的:(OJ_UVA,网络流_最小割,图论_最短路,ACM)