//http://blog.renren.com/share/327827934/14113666814?from=0101010202&ref=minifeed&sfet=102&fin=1&ff_id=327827934
//搞懂了斯坦纳树,这道题就基本上能够解决了。有一个处理就是,每个点成为井的花费怎么处理。如果直接每次SPFA的时候都加上的话,显然会被重复计算。
//由于开始想到的是费用流,所以自己在处理这个问题的时候就没有挣扎了。建立一个源点0,连接各点,
//而与各点之间的路程的花费就是各点成为井的花费。这样就能很好处理被重复计算的问题了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<algorithm>
#define INF 999999999
#define MAX 1010
#define MAX_STATUS 1<<6
using namespace std;
struct EDGE
{
int v ,w;
int next;
}edges[MAX*13];
struct NODE
{
int x ,y;
};
int head[MAX] ,cnt;
int n ,m ,p;
int value[MAX];
int status;//表示0~n号节点都被选择时的状态+1
int dis[MAX][MAX_STATUS] ,situation[MAX] ,vis[MAX][MAX_STATUS] ,dp;
//dis[i][j]表示以i节点为根选择点集状态为j时的最小值;situation[i]表示i节点对应的状态;vis[i][j]表示i节点为点集j时是否在队列中
queue<NODE> q;
void init()
{
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
memset(situation,0,sizeof(situation));
cnt = 0;
status = 1<<(n + 1);
for(int i = 0;i <= n + m;i++)
{
for(int j = 0;j <= status;j++)
{
dis[i][j] = INF;
}
}
for(int i = 0;i <= n;i++)///用二进制来表示状态
{
situation[i] = 1<<i;
dis[i][situation[i]] = 0;
}//i为根;
}
void add_edges(int u ,int v ,int w)
{
edges[cnt].v = v;
edges[cnt].w = w;
edges[cnt].next = head[u];
head[u] = cnt;
cnt++;
edges[cnt].v = u;
edges[cnt].w = w;
edges[cnt].next = head[v];
head[v] = cnt;
cnt++;
}
void SPFA()
{
NODE temp ,newd;
while(!q.empty())
{
temp = q.front();
q.pop();
vis[temp.x][temp.y] = 0;
for(int i = head[temp.x];i!=-1;i = edges[i].next)
{
int v ,situ;
v = edges[i].v;
situ = temp.y | situation[v];///状态加上v点的状态。
if(dis[temp.x][temp.y] + edges[i].w < dis[v][situ])///以i为跟,有状态j的点集的最小权值
{
dis[v][situ] = dis[temp.x][temp.y] + edges[i].w;///开数组记录。
if(situ==temp.y && !vis[v][situ])///为什么有这一条?
{
newd.x = v;
newd.y = situ;
q.push(newd);
vis[v][situ] = 1;///入栈的是根和状态。
}
}
}
}
}
void Steiner_Tree()
{
NODE temp;
for(int i = 0;i < status;i++)
{
for(int j = 0;j <= n + m;j++)
{
for(int k = i;k;k = (k - 1) & i)///(k-1)&i是什么?
{
dis[j][i] = min(dis[j][i],dis[j][k|situation[j]]+dis[j][(i-k)|situation[j]]);///补集
}
if(dis[j][i]!=INF)
{
temp.x = j;
temp.y = i;
q.push(temp);
vis[j][i] = 1;
}
}
SPFA();
}
}
int DP()
{
dp = INF;
for(int j = 0;j <= n+m;j++)
{
dp = min(dp,dis[j][status-1]);
}
return dp;
}
int main()
{
int u ,v ,w;
while(~scanf("%d%d%d",&n,&m,&p))
{
init();
for(int i = 1;i <= m + n;i++)
{
scanf("%d",&value[i]);
add_edges(0,i,value[i]);
}
for(int i = 0;i < p;i++)
{
scanf("%d%d%d",&u,&v,&w);
add_edges(u,v,w);
}
Steiner_Tree();
printf("%d\n",DP());
}
return 0;
}
HDU 3311 stainer树
最新推荐文章于 2019-06-04 20:27:22 发布