给出一副无向图,每条边都有一个权值且均未开通,先可以随便取一个起点,要开通一些边,使它成为一个连通图,开通一条边的代价为权值*起点到它的点的个数(起点也算),求最小代价.
考试时想到的是一种十分暴力的状压dp,用八进制压缩每一个点到起点的距离,复杂度为(8^n),无论是时间还是空间都还是很紧张,但还是顺利地拿到了70分.
正确方法是2^n状压,以起点为根节点建树,一层一层更新,枚举每一层所有的更新方法,用距离它最短的已更新的点去更新(不一定是上一层,因为如果是上一层以上的,则在更新那一层之前时已经更新,不会留到现在).
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
using namespace std;
int mm[20][20],n,m,ans,mn,d[20],dp[16777220],eig[]={1,8,64,512,4096,32768,262144,2097152,16777216};
inline void wj()
{
freopen("treasure.in","r",stdin);
freopen("treasure.out","w",stdout);
}
inline int qw(int u,int v)
{
u/=eig[v-1];
return u%8;
}
inline int dfs(int zt)
{
if(dp[zt]!=-1) return dp[zt];
register int i,j,k,res=INF;
bool have=0;
for(i=1;i<=n;++i)
{
if(qw(zt,i)!=7) continue;
have=1;
for(j=1;j<=n;++j)
{
k=qw(zt,j);
if(i==j||k+1>=7||mm[i][j]==INF) continue;
res=min(res,mm[i][j]*(k+1)+dfs(zt-(6-k)*eig[i-1]));
}
}
if(!have) return 0;
dp[zt]=res;
return res;
}
inline void read(int &u)
{
u=0;
register char ch=getchar();
for(;ch<'0';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar())
{
u=(u*10+ch-'0');
}
}
int main()
{
// wj();
register int i,p,q,o;
ans=INF;
memset(mm,INF,sizeof(mm));
memset(dp,-1,sizeof(dp));
read(n),read(m);
for(i=1;i<=m;++i)
{
read(p),read(q),read(o);
mm[p][q]=mm[q][p]=min(mm[p][q],o);
}
for(i=1;i<=n;++i)
{
ans=min(ans,dfs(((1 << (n*3))-1)-7*eig[i-1]));
}
printf("%d",ans);
}
#include
#include
#include
#include
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
ll n,m,dp[20][5000],bn[20][20],ans,num[20],num2[20],nn,aa[20],an1[20][5000],an2[20][5000],dee;
bool have;
vector<ll>jl[5000];
void get(ll now,ll sum1,ll sum2)
{
if(now==nn+1)
{
aa[dee]++;
an1[dee][aa[dee]]=sum1;
an2[dee][aa[dee]]=sum2;
return;
}
get(now+1,sum1|(1 << (num[now]-1)),sum2+num2[now]);
get(now+1,sum1,sum2);
}
ll dfs(ll deep,ll zt)
{
if(zt==(1 << n)-1) return 0;
if(deep>n) return INF;
if(dp[deep][zt]!=-1) return dp[deep][zt];
ll i,j,k,res=INF,mn;
nn=0;
for(i=1; i<=n; i++)
{
if((1 << (i-1))&zt) continue;
mn=INF;
for(k=0; k
{
j=jl[zt][k];
mn=min(mn,bn[i][j]);
}
if(mn==INF) continue;
nn++;
num[nn]=i;
num2[nn]=mn;
}
aa[deep]=0;
dee=deep;
get(1,0,0);
for(i=1; i<=aa[deep]; i++)
{
if(!an1[deep][i]) continue;
res=min(res,dfs(deep+1,an1[deep][i]|zt)+(deep+1)*an2[deep][i]);
}
dp[deep][zt]=res;
return res;
}
int main()
{
register ll i,j,p,q,o;
memset(bn,INF,sizeof(bn));
memset(dp,-1,sizeof(dp));
cin>>n>>m;
for(i=1; i<=(1 << n)-1; i++)
{
jl[i].clear();
for(j=1; j<=n; j++)
{
if(i&(1 << (j-1)))
jl[i].push_back(j);
}
}
for(i=1; i<=m; i++)
{
scanf("%lld%lld%lld",&p,&q,&o);
bn[p][q]=bn[q][p]=min(bn[p][q],o);
}
ans=INF;
for(i=1; i<=n; i++)
{
ans=min(ans,dfs(0,(1 << (i-1))));
}
printf("%lld",ans);
}