您的位置:首页 > 编程语言 > Java开发

HDU 4085 Peach Blossom Spring

2017-03-29 10:18 447 查看
斯坦纳树。

最后可以是森林,在计算出每个联通状态的最小费用后,还需要进行一次$dp$。

#include<bits/stdc++.h>
using namespace std;

const int INF=0x7FFFFFFF;
int T,n,m,k;
vector<int>g[60];
int val[60][60],id[60],d[60][1200],dp[1200];
int f[60*10000];
queue<int>Q;

void spfa()
{
while(!Q.empty())
{
int h = Q.front(); Q.pop(); f[h]=0;
int x=h/10000,y=h%10000;
for(int i=0;i<g[x].size();i++)
{
int to = g[x][i];

if(to<2*k)
{
if(((1<<to)&y)==0)
{
if(d[x][y]+val[x][to]<d[to][y|(1<<to)])
d[to][y|(1<<to)]=d[x][y]+val[x][to];
}
}

else
{
if(d[x][y]+val[x][to]<d[to][y])
{
d[to][y] = d[x][y]+val[x][to];
if(f[to*10000+y]==0)
{
f[to*10000+y]=1;
Q.push(to*10000+y);
}
}
}
}
}
}

bool check(int x)
{
int sum1=0,sum2=0;
for(int i=0;i<=k-1;i++) if(x&(1<<i)) sum1++;
for(int i=k;i<=2*k-1;i++) if(x&(1<<i)) sum2++;
if(sum1==sum2) return 1;
return 0;
}

int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&k);

for(int i=0;i<n;i++)
{
id[i]=i;
g[i].clear();
}

id[k]=n-k; for(int i=k+1;i<=2*k-1;i++) id[i]=id[i-1]+1;
id[n-k]=k; for(int i=n-k+1;i<=n-1;i++) id[i]=id[i-1]+1;

for(int i=0;i<n;i++)
for(int j=0;j<n;j++) val[i][j]=INF;
memset(f,0,sizeof f);

for(int i=1;i<=m;i++)
{
int a,b,c; scanf("%d%d%d",&a,&b,&c);
a--; b--; a=id[a]; b=id[b];
val[a][b]=min(val[a][b],c);
val[b][a]=val[a][b];
g[a].push_back(b);
g[b].push_back(a);
}

int st = 1<<(2*k);

for(int j=0;j<st;j++)
for(int i=0;i<n;i++) d[i][j]=INF;

for(int i=0;i<n;i++)
{
if(i<2*k) d[i][1<<i]=0;
else d[i][0]=0;
}

for(int j=0;j<st;j++)
{
for(int i=0;i<n;i++)
{
if(i<2*k)
{
if(((1<<i)&j)==0) continue;
for (int x = j; x; x = (x-1)&j)
{
int A=x ,B=j-A;
if(d[i][A|(1<<i)]!=INF&&d[i][B|(1<<i)]!=INF)
d[i][j] = min(d[i][j], d[i][A|(1<<i)]+d[i][B|(1<<i)]);
}
}
else
{
for (int x = j; x; x = (x-1)&j)
{
int A=x ,B=j-A;
if(d[i][A]!=INF&&d[i][B]!=INF)
d[i][j] = min(d[i][j], d[i][A]+d[i][B]);
}
}

if(d[i][j]!=INF) Q.push(i*10000+j);
}
spfa();
}

for(int j=0;j<st;j++)
{
dp[j]=INF;
for(int i=0;i<n;i++) dp[j]=min(dp[j],d[i][j]);
}

for(int j=0;j<st;j++)
{
for (int x = j; x; x = (x-1)&j)
{
int A=x ,B=j-A;
if(check(A)&&check(B)&&dp[A]!=INF&&dp[B]!=INF)
dp[j]=min(dp[j],dp[A]+dp[B]);
}
}

if(dp[st-1]!=INF) printf("%d\n",dp[st-1]);
else printf("No solution\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: