题目地址: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;
}