https://cn.vjudge.net/problem/HDU-3311
題意:
n 個和尚所住地各有一口井,另有 m 處也有口井,這 n + m 口井的挖掘需要花費,另外有 p 條路線連接這些井,問如何修路和挖掘使每個和尚都有水且總花費最小。
分析:
n + m 個點選 n 個點的最小生成樹,但是要考慮到有可能出現這樣總花費最小的情況:n 個和尚就在自己的所在地挖井,不造路,此時是不存在樹的。
不過我們仔細分析,可以建一個超級源點 0,分別連接着 n + m 口井,路徑值就是挖掘當前井的花費。
接下來就很簡單了。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <bitset>
#include <map>
typedef long long int ll;
const int MOD = (int)1e9 + 7;
const int INF = 99999999;
using namespace std;
struct Edge
{
int v, w;
int next;
};
int n, m, p;
int cnt;
int top;
int head[1010];
Edge edge[20000];
int state[1010];
int dp[1010][1 << 6];
int vis[1010][1 << 6];
queue<pair<int, int> > Q;
void add_edge(int u, int v, int w)
{
edge[cnt].v = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
edge[cnt].v = u;
edge[cnt].w = w;
edge[cnt].next = head[v];
head[v] = cnt++;
}
void spfa()
{
while (!Q.empty())
{
int u = Q.front().first;
int s = Q.front().second;
Q.pop();
vis[u][s] = 0;
for (int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
int w = edge[i].w;
int ss = s | state[v];
if (dp[v][ss] > dp[u][s] + w)
{
dp[v][ss] = dp[u][s] + w;
if (ss == s && !vis[v][ss])
{
Q.push(make_pair(v, ss));
vis[v][ss] = 1;
}
}
}
}
}
int main()
{
while (~scanf("%d%d%d", &n, &m, &p))
{
memset(head, -1, sizeof(head));
memset(vis, 0, sizeof(vis));
memset(state, 0, sizeof(state));
cnt = 0;
top = 1 << (n + 1);
for (int i = 0; i <= n + m; i++)
for (int j = 0; j < top; j++)
dp[i][j] = INF;
for (int i = 0; i <= n; i++)
{
state[i] = 1 << i;
dp[i][state[i]] = 0;
}
int w;
for (int i = 1; i <= (n + m); i++)
{
scanf("%d", &w);
add_edge(0, i, w); // 超級源點
}
int u, v;
for (int i = 0; i < p; i++)
{
scanf("%d%d%d", &u, &v, &w);
add_edge(u, v, w);
}
for (int i = 0; i < top; i++)
{
for (int j = 0; j <= (n + m); j++)
{
for (int sub = i; sub != 0; sub = (sub - 1) & i)
dp[j][i] = min(dp[j][i], dp[j][sub | state[j]] + dp[j][(i - sub) | state[j]]);
if (dp[j][i] < INF)
{
Q.push(make_pair(j, i));
vis[j][i] = 1;
}
}
spfa();
}
int res = INF;
for (int i = 0; i <= (n + m); i++)
res = min(res, dp[i][top - 1]);
printf("%d\n", res);
}
return 0;
}