[NOIP2017] Treasure (like pressure DP / blast search)

 

problem:

Xiaoming involved in archaeological excavations got a treasure map, the n marked treasure buried in the ground on the housing treasure map also shows that the n m between the road and the treasures they house for development length.

Xiao Ming personally determined to go digging treasure house of all treasures. However, each treasure house is very far from the ground, that is, open up a path to a treasure house from the ground is very difficult, and the road between the treasure house development is relatively much easier.

Xiao Ming's determination moved the sponsor, the sponsor decided to sponsor archaeological excavations free him from the ground to open up a channel of a treasure house, which houses treasures by Xiao Ming leading to a decision.

On this basis, Xiao Ming also need to consider how to cut the road between the treasure house. May have been dug out of the road traffic does not consume any price. Each cut out a new road, Xiao Ming will dig out the treasure by the piece of road can reach the treasure house with the archaeological team. In addition, Xiao Ming did not want to develop useless road, that road between the two have been excavated treasure house no longer develop.

The development of a new road at the cost of:

L×K

L represents the length of this road, on behalf of K to help you get through the treasure house from the sponsor to the number of the treasure house of this road start of treasure house elapsed (including sponsor to help you get through the treasure house and this path starting point treasure House).

Please write programs selected by the sponsors get through the treasures of the house and the road was dug after Xiao Ming, making the total cost of the project a minimum, and outputs the minimum value.

 

solution:

This question is do I count the calendar from the heart

N First, I see so small I would define the $ f [i] $ denote the set of all minimum cost traversal

               $ Dis [j] $ j indicates the depth of (I did not see it start to choose a tree, as well as depth ....)  

            $dp[i|(1<<j-1)]=min(dp[i|1<<j-1],dis[edge[k].st]*edge[k].val+dp[i])$ 其中终点为不在集合内的j 起点为在集合的st

                Then from there CCF honor lie 50 points .... 

                The reason is that the time complexity is high and dis array counted in question

code:

#include<stdio.h>
#include<cstdio> 
#include<algorithm> 
#include<cmath> 
#include<bits/stdc++.h>
using namespace std;
#define maxn 5555
#define maxnn 5000
#define ll long long 
ll dp[maxn];
int dis[maxn];
int tot=0;
int all;
struct node
{
    int st,en;
    int val;
}edge[maxnn];
int n,m;
void add(int a,int b,int c)
{
    edge[++tot].en=b;
    edge[tot].st=a;
    edge[tot].val=c;
}
void dfs(int v)
{
    for(int i=0;i<=n;i++)
    dis[i]=0;
    for(int i=0;i<=all;i++)
    {
        dp[i]=100000000000;
    }
    dis[v]=1;
    dp[1<<v-1]=0;
    for(int i=1<<v-1;i<=all;i++)
    {
        for(int j=1;j<=n;j++)
        {    
            if(((1<<j-1)&i)==0)
            {
                for(int k=1;k<=tot;k++)
                {
                    if((((1<<edge[k].st-1)&i)!=0)&&(edge[k].en==j)&&(dp[i|1<<j-1]>dis[edge[k].st]*edge[k].val+dp[i]))
                    {
                        dp[i|(1<<j-1)]=min(dp[i|1<<j-1],dis[edge[k].st]*edge[k].val+dp[i]);
                        dis[j]=dis[edge[k].st]+1;
                    }
                }
            }
            
        }
    }
}
int main()
{
    cin>>n>>m;
    int x,y,z;
    ll ans=100000000000;
    all=(1<<n)-1;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
        add(y,x,z);
    }
    for(int i=1;i<=n;i++)
    {
        dfs(i);
        ans=min(ans,dp[all]);
    }
    cout<<ans;
}

 

How to do?

We note that, in fact, we are not dis counted array is an array of depth does not count  

And a point is a point value from the depth of * VAL update weights from such a small and n is certainly defined two-dimensional array

So we have some $ f [i] [j] $ denotes the set of i and j minimum cost to the depth of the current discussion

State transition equation will come out

$dp[i|k][j]=min(dp[i|k][j],dp[i][j-1]+(j)*\sum k^i)$ 其中$\sum k^i $ 为深度为j的集合k到集合i的最小距离之和 
k是i的补集的子集 也就是包含了没有被讨论过的点
这里我们就要安利一波枚举子集的方法
for(int i=s,i;i=(i-1)&s)
(The set of elements is the original x 1) as well as a method of collection of elements wave rapidly removed
for(int i=s;i;i=i-(i&-i))
{
  int x=i&-i;          
}
 

It is said that this array with faster Oh and logg2

but

After a more than one hour of constant optimization card I was often stuck success 

luoguAC oj T 75pts   Buddha

 

code:

 

#include<stdio.h>
#include<cstdio> 
#include<algorithm> 
#include<cmath> 
#include<bits/stdc++.h>
using namespace std;
#define maxn 5555
#define maxnn 5000
#define ll long long 
ll dp[maxn][maxnn];
int sum[maxnn][maxnn];
int mapp[30][30];
int dis[maxnn][maxnn];
int tot=0;
int all;
int n,m;
int logg[1<<14];

inline void init()
{
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=all;j++)
        {
            dis[i][j]=10000000;
        }
    }
    for(int j=0;j<=all;j++)
    {
        int s0=j^all;
        for(int i=s0;i;i=(i)-(i&-i))
        {
            int x=i&-i;
            for(int k=j;k;k=k-(k&-k))
            {
                int u=k&-k;

                {
                    dis[logg[x]][j]=min(dis[logg[x]][j],mapp[logg[x]][logg[u]]);
                }
            }
        }    
    }
    for(int j=0;j<=all;j++)
    {
        int s=j^all;
        for(int u=s;u;u=((u-1)&s))
        for(int i=u;i;i=(i)-(i&-i))
        {
            int x=i&-i;
            {
                sum[u][j]+=dis[logg[x]][j];
            }
        }
    }
}
int main()
{
    cin>>n>>m;
    all=(1<<n)-1;
    for(int j=1;j<=n;j++)
    {
        logg[1<<j-1]=j;
    }
    for(int j=0;j<=n;j++)
    {
        for(int i=0;i<=n;i++)
        {
            if(i!=j) mapp[i][j]=100000000;
        }
    }
    int a,b,c;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        mapp[a][b]=min(mapp[a][b],c);
        mapp[b][a]=min(mapp[a][b],c);
    }
    init();
    ll ans=1000000000;
    for(int i=1;i<=n;i++)
    {
    for(int j=0;j<=n;j++)
    {
    for(int i=0;i<=all;i++)
        {
            dp[i][j]=1000000000;
        }
    }
    dp[1<<i-1][0]=0;
    for(int i=0;i<=all;i++)
    {
        for(int j=1;j<=n;j++)
        {
            int s0=(all^i);
            for(int k=s0;k;k=((k-1)&s0))
            {
                dp[i|k][j]=min(dp[i|k][j],dp[i][j-1]+(j)*sum[k][i]);
            }
        }
    }
    for(int j=0;j<=n;j++)
    {
         ans=min(ans,dp[all][j]);
    }
    }
    printf("%lld",ans);
}

 

My classmates to help me optimize card after a metaphysics

 


Finally, I found a magical solution    

Burst search

8 notice! The whole arrangement is actually very small then burst search ah

Oblack said that when seniors is the explosion took 90pts %%% search

Spend time: 0ms

We need to enumerate the root node and then in turn transferred back 

Once again demonstrated the importance of pruning burst search + 

code:

//
#include<bits/stdc++.h>
using namespace std;
#define maxnn 30
int tar[maxnn][maxnn];
int cnt=0;
int n,m;
int d[maxnn];
int vis[maxnn];
#define inf 1000000
int tmp=0,tot;
int ans=100000000;
int c[maxnn][maxnn];
int le[maxnn];
int p;
bool cmp(int a,int b){

    return c[p][a]<c[p][b];
} 
Void dfs ( int num, int node) 
{ 
    for ( int i = num; i <= cnt; i ++ ) 
    { 
        if (tot + tmp * the [screw [i]]> years) return ;
        for ( int j = node; j <= d [screw [i]]; j ++ ) 
        { 
            if (! on [tar [screw [i]] [j]]) 
            { 
                cnt ++ ; 
                am [cnt] = tar [am [i]] [j]; 
                tmp - = c [am [cnt]] [tar [am [cnt]] [ 1 ]]; 
                early= c + [am [i]] [am [cnt]] * a [am [i]]; 
                the [am [cnt]] = the [am [i]] + 1 ; 
                dfs (i, j + 1 ); 
                tot - = c [am [i]] [am [cnt]] * a [am [i]]; 
                the [am [cnt]] = 0 ; 
                tmp + = c [am [cnt]] [tar [am [cnt]] [ 1 ]]; 
                cnt - ; 
            } 
        } 
        Node = 1 ; 
    } 
    If (cnt == n) 
    { 
        if (tot <years) ans = tot;
        return ;
    }
}
int main()
{
    int x,y,z;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    {
        c[i][j]=inf;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        if(c[x][y]==inf)
        tar[x][++d[x]]=y,tar[y][++d[y]]=x;
        if(c[x][y]>z)
        {
            c[x][y]=z;
            c[y][x]=z;
        } 
    }
    for(int i=1;i<=n;i++)
    {
        p=i;
        sort(tar[i]+1,tar[i]+1+d[i],cmp);
        tmp+=c[i][tar[i][1]];
    }
    for(int i=1;i<=n;i++)
    {
        tot=0;
        cnt=1;
        vis[1]=i;
        le[i]=1;
        tmp-=c[i][tar[i][1]];
        dfs(1,1);
        le[i]=0;
        tmp+=c[i][tar[i][1]];
    }
    printf("%d",ans);
}

 

 

 summay:

* By this question, I think the question is not simple CCF exam-like pressure DP and enumerate take a subset of the set of elements and other operations

* Search is not explosive burst search is not too important to practice more explosive search




 

Guess you like

Origin www.cnblogs.com/OIEREDSION/p/11415885.html