noip2017宝藏

https://www.luogu.org/problemnew/show/3959
转载了【http://blog.csdn.net/KsCla/article/details/78554935】
这个思想真的是简单;
做完之后感觉自己是智障;
你看我们他妈是不是要记录2个信息
一个是当前联通块;
一个是当前联通块点的深度;
如果我们dp我们就要处理这2个东西;
那么我们记录当前联通块,然后移每一层为单位dp就可以了;
这个大佬讲的真的非常好;
而且还有一些关于二进制的骚操作;
唉,学识尚浅,智力偏低;

#include
#define U(x,y) ((x-1)*(K+1)+y)
using namespace std;
inline int RR(){int v=0,k=1;char c=0;while('0'>c||c>'9'){if(c=='-')k=-1;c=getchar();}while('0'<=c&&c<='9')v=(v<<3)+(v<<1)+c-48,c=getchar();return v*k;}
inline void W(int x){if(x<0)putchar('-'),x=-x;if(x>9)W(x/10);putchar(x%10+48);}
inline void WW(int x){W(x);puts("");}
inline void read(int &x,int &y){x=RR();y=RR();}
const int N=13,M=4100;
int t[N][M],g[M][M],f[N][M],a[N][N];
int n,m,x,y,z,K,ans;
void make(){
    for(int i=0;i<=K;i++)
        for(int j=1;j<=n;j++){
            t[j][i]=f[j][i]=1e6;
            for(int k=1;k<=n;k++)
                if((i&(1<<(k-1))))t[j][i]=min(t[j][i],a[k][j]);
        }
    for(int i=0;i<=K;i++)
        for(int j=0;j<=K;j++)
            g[i][j]=1e6;
    for(int i=1;i<=K;i++){
        int j=i&(i-1);
        while(j){
            g[j][i]=0;
            for(int k=1;k<=n;k++)
                if((i&(1<<(k-1))))g[j][i]+=t[k][j];
            j=i&(j-1);
        }
    }           
}
int main()
{
    read(n,m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            a[i][j]=1e6;
    for(int i=1;i<=n;i++)a[i][i]=0;
    while(m--){
        read(x,y);z=RR();
        a[x][y]=min(a[x][y],z);
        a[y][x]=a[x][y];
    }
    K=(1<1;
    make();
    for(int i=1;i<=n;i++)f[1][(1<<(i-1))]=0;
    for(int i=2;i<=n;i++)
        for(int j=1;j<=K;j++){
            int s=j&(j-1);
            while(s){
                f[i][j]=min(f[i][j],f[i-1][s]+g[s][j]*(i-1));
                s=j&(s-1);
            }
        }
    ans=1e6;
    for(int i=1;i<=n;i++)ans=min(ans,f[i][K]);
    WW(ans);
}

然后给你们看看xjb的力量;
讲道理我noip的时候真的是好像没学过oi一样
https://www.luogu.org/record/show?rid=4731812
唉,人菜则颓,人颓则菜;

你可能感兴趣的:(状压dp,搜索)