杭电3339————最短路(SPFA)+ 01背包

来源:互联网 发布:dw制作淘宝导航条 编辑:程序博客网 时间:2024/05/16 08:26

题目链接:点击打开链接


题目大致如下。

每一个核电站都有一定的电力值,你需要控制这些核电站,使得你控制的电力值的大小超过所有核电站电力值的一半,在保证这个前提的基础上,寻找最短路。

控制核电站,需要一些坦克,坦克的数量是无限的(!注意这个地方!)


一开始的思路:

做一个如下的结构体:

typedef struct{    int dist;//存取s源点到这个核电站的最短路    int power;//存取s源点到这个核电站的总power值}Node;

跑一遍spfa找到最短路的同时,记录最短路经过的点的总电力值。然后将dist数组从小到大排序,只要到某一个站点的电力值超过一半就保证了最短路且控制了电网,直接输出就好了。

然后就WA了。

我的这种思路试用于至于一辆坦克,走一遍的那种,但实际上我们拥有多辆坦克,那么就不可以这么做了。

在看了别人的解答之后,想明白了这个题目在求出源点到所有结点的基础上,用一次01背包就可以解决问题。

稍微解释一下为什么01背包:

对于每一个站点,我们可以选择占领或者不占领。占领一个站点需要花费的费用为到该点的最短路,获得的价值即为该点的电力值。

这样一说,很显然是01背包的思路:

#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <cmath>#include <queue>#define maxn 105#define INF 0x7ffffffusing namespace std;int dist[maxn];int G[maxn][maxn];int n,m;int power[maxn],total_power;int dp[10010];//注意这个数组的大小queue<int> Q;int Min(int x,int y){    return (x < y) ? x : y;}int Max(int x,int y){    return (x > y) ? x : y;}void init(){    for(int i =  0 ; i < maxn ; ++i){        for(int j = 0 ; j < maxn ; ++j){            if(i == j)                G[i][j] = 0;            else                G[i][j] = INF;        }    }    memset(power,0,sizeof(power));    memset(dp,0,sizeof(dp));    total_power = 0;}void SPFA(){    bool inq[maxn];//inqueue    memset(inq,false,sizeof(inq));    for(int i = 0 ; i <= n ; ++i)        dist[i] = INF;    while(!Q.empty())        Q.pop();//每次SPFA前清空队列    Q.push(0);    inq[0] = true,dist[0] = 0;    while(!Q.empty())    {        int now = Q.front();        Q.pop();        inq[now] = false;        for(int next = 0 ; next <= n ; ++next)        {            if(G[now][next] != INF)//连通的            {                if(dist[now] + G[now][next] < dist[next])//relax                {                    dist[next] = dist[now] + G[now][next];                    if(!inq[next])                    {                        inq[next] = true;                        Q.push(next);                    }                }            }        }    }}int main(){    int casenum;    int v1,v2,weight,half;    cin >> casenum;    while(casenum--){        cin >> n >> m;        init();        while(m--){            cin >> v1 >> v2 >> weight;            G[v2][v1] = G[v1][v2] = Min(G[v1][v2],weight);        }        for(int i = 1 ; i <= n ; ++i){//读取power值            cin >> power[i];            total_power += power[i];        }        half = total_power / 2;        weight = 0;        SPFA();        for(int i = 1 ; i <= n ; ++i)            if(dist[i] != INF)                weight += dist[i];        for(int i = 1 ; i <= n ; ++i)//对于每一个站点            for(int j = weight ; j >= dist[i] ; --j)                dp[j] = Max(dp[j],dp[j-dist[i]]+power[i]);        int flag = -1;        for(int i = 0 ; i <= weight ; ++i){            if(dp[i] > half){                flag = i;                break;            }        }        if(flag == -1)            cout << "impossible" << endl;        else            cout << flag << endl;    }    return 0;}

附上之前的错误代码:

(思路还好,只不过题目理解错了)

#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <cmath>#include <queue>#define maxn 105#define INF 0x7ffffffusing namespace std;typedef struct{    int dist;//存取s源点到这个核电站的最短路    int power;//存取s源点到这个核电站的总power值}Node;Node node[maxn];int G[maxn][maxn];int n,m;int power[maxn],total_power;queue<int> Q;int Min(int x,int y){    return (x < y) ? x : y;}void init(){    for(int i =  0 ; i < maxn ; ++i)        for(int j = 0 ; j < maxn ; ++j)            G[i][j] = INF;    memset(power,0,sizeof(power));    total_power = 0;}void SPFA(){    bool inq[maxn];//inqueue    memset(inq,false,sizeof(inq));    for(int i = 0 ; i <= n ; ++i){        node[i].dist = INF;        node[i].power = 0;    }    while(!Q.empty())        Q.pop();//每次SPFA前清空队列    Q.push(0);    inq[0] = true,node[0].dist = 0;    while(!Q.empty())    {        int now = Q.front();        Q.pop();        inq[now] = false;        for(int next = 0 ; next <= n ; ++next)        {            if(G[now][next] != INF)//连通的            {                if(node[now].dist + G[now][next] < node[next].dist)//relax                {                    node[next].dist = node[now].dist + G[now][next];                    node[next].power = node[now].power + power[next];//这个地方很重要啊                    if(!inq[next])                    {                        inq[next] = true;                        Q.push(next);                    }                }            }        }    }}int cmp(const void *a,const void *b){    Node *A = (Node*)a;    Node *B = (Node*)b;    return (A->dist > B->dist);}int main(){    int casenum;    int v1,v2,weight,half;    cin >> casenum;    while(casenum--){        cin >> n >> m;        init();        while(m--){            cin >> v1 >> v2 >> weight;            G[v2][v1] = G[v1][v2] = Min(G[v1][v2],weight);        }        for(int i = 1 ; i <= n ; ++i){//读取power值            cin >> power[i];            total_power += power[i];        }        SPFA();        qsort(node,n,sizeof(Node),cmp);        if(total_power % 2 == 0)            half = total_power / 2 + 1;        else            half = (total_power + 1) / 2;        int flag = -1;        for(int i = 1 ; i <= n ; ++i){            if(node[i].power >= half && node[i].dist != INF){                flag = i;                break;            }        }        if(flag == -1)            cout << "impossible" << endl;        else            cout << node[flag].dist << endl;    }    return 0;}





0 0
原创粉丝点击