zoukankan      html  css  js  c++  java
  • HDU 3339 In Action

    题目大意:有n个电站,每个电站都有一定的电量,电站之间有一定距离,我们要从0点出发去占领一些电站,使得占领的电站电量之和超过总电量的一半,求达到条件所要走的最短距离。如果可能的话,输出距离,否则输出不可能。

    题解:首先计算所有点到起点的最短路,就得到了代价,现在又有价值,那么就是一个01背包~

    #include <cstdio>   
    #include <cstring>  
    #include <utility>  
    #include <queue>  
    #include <algorithm>
    using namespace std;  
    const int N=20005;  
    const int INF=~0U>>1;  
    typedef pair<int,int>seg;  
    priority_queue<seg,vector<seg>,greater<seg> >q;     
    int sumv,sum,va[N],f[N],begin,end,d[N],head[N],u[N],v[N],w[N],next[N],n,m,a,b,c; 
    bool flag,vis[N];  
    void build(){  
        memset(head,-1,sizeof(head)); 
        for(int e=1;e<=m;e++){  
            scanf("%d%d%d",&u[e],&v[e],&w[e]);  
            u[e+m]=v[e]; v[e+m]=u[e]; w[e+m]=w[e];  
            next[e]=head[u[e]]; head[u[e]]=e;  
            next[e+m]=head[u[e+m]]; head[u[e+m]]=e+m;  
        }  
    }     
    void Dijkstra(int src){  
        memset(vis,0,sizeof(vis));  
        for(int i=0;i<=n;i++) d[i]=INF;  
        d[src]=0;  
        q.push(make_pair(d[src],src));  
        while(!q.empty()){  
            seg now=q.top(); q.pop();  
            int x=now.second;  
            if(vis[x]) continue; vis[x]=true;  
            for(int e=head[x];e!=-1;e=next[e]) 
            if(d[v[e]]>d[x]+w[e]){  
                d[v[e]]=d[x]+w[e];  
                q.push(make_pair(d[v[e]],v[e]));  
            }   
        }  
    }      
    void ZeroOnePack(int n,int v){
         memset(f,0,sizeof(f));
         for(int i=0;i<=n;i++)
             for(int j=v;j>=d[i];j--)
                 f[j]=max(f[j],f[j-d[i]]+va[i]);
    }
    int main(){  
        scanf("%d",&n);
        while(~scanf("%d%d",&n,&m)){
            int sum=sumv=0;
            build();
            Dijkstra(0);
            for(int i=1;i<=n;i++)scanf("%d",&va[i]),sumv+=va[i];
            for(int i=1;i<=n;i++)if(d[i]!=INF)sum+=d[i];
            ZeroOnePack(n,sum); 
            flag=false;
            if ((sumv&1)==0) sumv=sumv>>1;
            else sumv=(sumv>>1)+1;
            for(int i=0;i<=sum;i++){
                if(f[i]>=sumv){
                    printf("%d
    ",i); 
                    flag=true; break;
                }
            }
            if(!flag)puts("impossible");
        }  
        return 0;  
    }
    
  • 相关阅读:
    小阳买水果
    单调队列+dp
    最长的合法序列(栈+dp)
    A. 打印收费
    数位dp(K好数)
    Floyd(选地址)
    最短路计数
    线段树维护区间01
    解密(拓展欧几里的)
    树、森林的遍历
  • 原文地址:https://www.cnblogs.com/forever97/p/3619422.html
Copyright © 2011-2022 走看看