遥想当年。
SCOI考一个状压就差不多了。
且看今宵。
NOIP都得考上状压dp。
好了这个状压比较好想。
首先供上我联赛的时候写的代码:
->
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll g[20][20]={0};
int a[20]={0};
int n,m;
ll ans=1000000000000;
int vis[20]={0};
void dfs(int u,ll sum,int tot){
// cout<<u<<" "<<sum<<" "<<tot<<" "<<n<<endl;
if(tot==n){
ans=min(ans,sum);
return;
}
if(ans<=sum)
return;
for(int i=1;i<=n;++i){
if(!vis[i])
continue;
for(int j=1;j<=n;++j)
if(g[i][j]<=500000&&!vis[j]){
a[j]=a[i]+1;
vis[j]=1;
dfs(j,sum+(ll)a[j]*g[i][j],tot+1);
vis[j]=0;
a[j]=0;
}
}
}
int main(){
memset(g,0x3f,sizeof(g));
scanf("%d%d",&n,&m);
// read(n);
// read(m);
for(int i=1;i<=m;++i){
int u,v;
ll w;
scanf("%d%d%lld",&u,&v,&w);
g[u][v]=min(g[u][v],w);
g[v][u]=min(g[v][u],w);
}
// cout<<"ewquy89i2o34"<<endl;
// vis[1]=1;
// dfs(1,0,1);
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
memset(a,0,sizeof(a));
vis[i]=1;
dfs(i,0,1);
// cout<<ans<<endl;
}
printf("%lld",ans);
return 0;
}
没有压,因为那个时候我很弱。
但是这个题我得了70.全省比我高的也就10来个。
好了这说明你会暴力也不错啊!!!!
那么这个时候呀,怎么状态压缩呢?
好了我们来看一下:只需要加三句话。
第一还记得迪杰斯特拉算法吗?
我们怎么保证算法效率的?
松弛原理。
这就是为什么Astar还是慢一些,因为你无法松弛。
于是考虑一个当前状态的中间值。
这就类似我原本的剪枝,只不过只剪了一次生成树,就是答案层,于是只有70,那么中间层就只能状态压缩了。
#include<bits/stdc++.h>
using namespace std;
inline void read(int &x){
x=0;
int f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
x*=f;
}
const int INF=1e9+7;
int dp[1<<13]={0};
int g[15][15]={0};
int dis[15]={0};
int n,m;
void dfs(int x){
for(int i=1;i<=n;i++){
if(!((1<<(i-1))&x))
continue;
for(int j=1;j<=n;j++){
if(!((1<<(j-1))&x)&&g[i][j]){
if(dp[(1<<(j-1)|x)]>dp[x]+(dis[i])*g[i][j]){
int t=dis[j];
dis[j]=dis[i]+1;
dp[(1<<(j-1)|x)]=dp[x]+dis[i]*g[i][j];
dfs((1<<(j-1)|x));
dis[j]=t;
}
}
}
}
}
int main(){
int ans=INF;
read(n);
read(m);
for(int i=1;i<=m;i++){
int u,v,w;
read(u);
read(v);
read(w);
if(!g[u][v]||g[u][v]>w){
g[u][v]=g[v][u]=w;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=(1<<n)-1;j++){
dp[j]=INF;
}
dis[i]=1;
dp[(1<<(i-1))]=0;
dfs((1<<(i-1)));
// cout<<dp[(1<<n)-1];
ans=min(ans,dp[(1<<n)-1]);
}
cout<<ans<<endl;
}
注意看DP数组,他就是存储了当前的一度最优质,这就达到了减去n次生成树的办法。