今天学习了斯坦纳树,主要是求一个最短网络。
而得到的最短网络必定是以树。
一个操作是 将两个子集 合并
一个操作是 在一个子集 加上一个点
dp[N][mark] N 代表当前在那个点上去扩张 mark 代表当前有所需K个子树的状态。
由于每一个点 都有可能是最优的扩张点 所以可以达到最优。
枚举子树的形态:dp[ i ][ j ]=min{ dp[ i ][ j ],dp[ i ][ k ]+dp[ i ][ l ] },其中k和l是对j的一个划分。
按照边进行松弛:dp[ i ][ j ]=min{ dp[ i ][ j ],dp[ i' ][ j ]+w[ i ][ i' ] },其中i和i'之间有边相连。
而对于同一层进行spfa 进行优化
for(int i=0;i<tot;i++)
{
for(int j=1;j<=n;j++)
{
for(int l=i-1&i;l;l=l-1&i)
f[i][j]=min(f[l|sta[j]][j]+f[i-l|sta[j]][j],f[i][j]);
if(f[i][j]<INF)
{
node temp;
temp.x=i;
temp.y=j;
inq[i][j]=1;
q.push(temp);
}
}
spfa();
}
void spfa()
{
while(!q.empty())
{
node mf=q.front();
q.pop();
inq[mf.x][mf.y]=false;
for(int u=head[mf.y];u!=-1;u=e[u].next)
{
int cur=mf.x|sta[e[u].v];
if(f[mf.x][mf.y]+e[u].c<f[cur][e[u].v])
{
f[cur][e[u].v]=f[mf.x][mf.y]+e[u].c;
if(cur==mf.x&&!inq[cur][e[u].v])
{
inq[cur][e[u].v]=1;
node temp;
temp.x=cur;
temp.y=e[u].v;
q.push(temp);
}
}
}
}
}
= = = = = == = = = = = == = = = = == = = == = == = = = =
for(int i=0;i<tot;i++)
{
for(int j=1;j<=n;j++)
{
dp[i]=min(dp[i],f[i][j]);
}
}
得到dp 即可得到最优森林
HDU 4085
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <queue>
using namespace std;
#define maxn 55
#define maxa 3005
#define INF 0x3f3f3f3f
struct node
{
int x;
int y;
};
struct edge
{
int u;
int v;
int c;
int next;
};
edge e[maxa];
int head[maxn],cnt;
int f[1<<11][maxn];
int dp[1<<11];
int sta[maxn];
bool inq[1<<11][maxn];
queue<node> q;
void addedge(int u,int v,int c)
{
e[cnt].u=u;
e[cnt].v=v;
e[cnt].c=c;
e[cnt].next=head[u];
head[u]=cnt++;
e[cnt].u=v;
e[cnt].v=u;
e[cnt].c=c;
e[cnt].next=head[v];
head[v]=cnt++;
}
void spfa()
{
while(!q.empty())
{
node mf=q.front();
q.pop();
inq[mf.x][mf.y]=false;
for(int u=head[mf.y];u!=-1;u=e[u].next)
{
int cur=mf.x|sta[e[u].v];
if(f[mf.x][mf.y]+e[u].c<f[cur][e[u].v])
{
f[cur][e[u].v]=f[mf.x][mf.y]+e[u].c;
if(cur==mf.x&&!inq[cur][e[u].v])
{
inq[cur][e[u].v]=1;
node temp;
temp.x=cur;
temp.y=e[u].v;
q.push(temp);
}
}
}
}
}
bool judge(int x,int y)
{
int a=0,a1=0,a2=0;
while(x)
{
if(x%2)
{
if(a<y)
{
a1++;
}
else
a2++;
}
x/=2;
a++;
}
return a1==a2;
}
int main()
{
int t,n,m,k,u,v,c;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
cnt=0;
memset(head,-1,sizeof(head));
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++)
{
sta[i]=0;
if(i<=k) sta[i]=1<<(i-1);
if(i>=n-k+1) sta[i]=1<<(i-(n-k+1)+k);
f[sta[i]][i]=0;
}
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&c);
addedge(u,v,c);
}
memset(inq,0,sizeof(inq));
int tot=1<<(2*k);
for(int i=0;i<tot;i++)
{
for(int j=1;j<=n;j++)
{
for(int l=i-1&i;l;l=l-1&i)
f[i][j]=min(f[l|sta[j]][j]+f[i-l|sta[j]][j],f[i][j]);
if(f[i][j]<INF)
{
node temp;
temp.x=i;
temp.y=j;
inq[i][j]=1;
q.push(temp);
}
}
spfa();
}
memset(dp,0x3f,sizeof(dp));
for(int i=0;i<tot;i++)
{
for(int j=1;j<=n;j++)
{
dp[i]=min(dp[i],f[i][j]);
}
}
for(int i=0;i<tot;i++)
{
if(judge(i,k))
{
for(int j=i-1&i;j;j=j-1&i)
{
if(judge(j,k)&&judge(i-j,k))
dp[i]=min(dp[i],dp[j]+dp[i-j]);
}
}
}
if(dp[tot-1]!=INF)
printf("%d\n",dp[tot-1]);
else
puts("No solution");
}
return 0;
}
hdu 3311
这题是看了别人代码的 由于不知道stnt
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <queue>
using namespace std;
#define maxn 2010
#define INF 0x3f3f3f3f
struct node
{
int x;
int y;
};
int f[205][maxn];
int dp[205];
int n,m,l,x,cnt;
int head[maxn];
int sta[maxn];
queue<node> q;
int inq[205][maxn];
struct edge
{
int u;
int v;
int c;
int next;
};
edge e[maxn*10];
void addedge(int u,int v,int c)
{
e[cnt].u=u;
e[cnt].v=v;
e[cnt].c=c;
e[cnt].next=head[u];
head[u]=cnt;
cnt++;
e[cnt].u=v;
e[cnt].v=u;
e[cnt].c=c;
e[cnt].next=head[v];
head[v]=cnt;
cnt++;
}
void spfa()
{
while(!q.empty())
{
node fr=q.front();
q.pop();
inq[fr.x][fr.y]=0;
for(int u=head[fr.y];u!=-1;u=e[u].next)
{
int x=fr.x|sta[e[u].v];
int y=e[u].v;
if(f[x][y]>f[fr.x][fr.y]+e[u].c)
{
f[x][y]=f[fr.x][fr.y]+e[u].c;
if(!inq[x][y]&&x==fr.x)
{
inq[x][y]=1;
node temp;
temp.x=x;
temp.y=y;
q.push(temp);
}
}
}
}
}
int main()
{
int u,v,c;
while(scanf("%d%d%d",&l,&m,&n)!=EOF)
{
cnt=0;
memset(f,0x3f,sizeof(f));
memset(head,-1,sizeof(head));
for(int i=1;i<=l;i++)
{
scanf("%d",&x);
f[1<<(i-1)][i]=0;
f[(1<<(i-1))|(1<<l)][i]=x;
sta[i]=1<<(i-1);
}
for(int i=l+1;i<=l+m;i++)
{
scanf("%d",&x);
f[1<<l][i]=x;
sta[i]=0;
}
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&u,&v,&c);
addedge(u,v,c);
}
int tot=1<<(l+1);
memset(inq,0,sizeof(inq));
for(int i=0;i<tot;i++)
{
for(int j=1;j<=l+m;j++)
{
for(int k=i&i-1;k;k=(k-1)&i)
f[i][j]=min(f[i][j],f[k|sta[j]][j]+f[i-k|sta[j]][j]);
if(f[i][j]<INF)
{
node temp;
temp.x=i;
temp.y=j;
inq[i][j]=1;
q.push(temp);
}
}
spfa();
}
memset(dp,0x3f,sizeof(dp));
for(int i = 0; i < tot; i ++)
for(int j = 1; j <= l + m; j ++)
dp[i] = min(dp[i], f[i][j]);
for(int i = 0; i < tot; i ++)
if(i & 1 << l)
{
for(int j = i - 1 & i; j; j = j - 1 & i)
if(j & 1 << l)
dp[i] = min(dp[i], dp[j] + dp[i - j | 1 << l]);
}
printf("%d\n",dp[tot-1]);
}
return 0;
}