题目链接:点击打开链接
题目大致如下。
每一个核电站都有一定的电力值,你需要控制这些核电站,使得你控制的电力值的大小超过所有核电站电力值的一半,在保证这个前提的基础上,寻找最短路。
控制核电站,需要一些坦克,坦克的数量是无限的(!注意这个地方!)
一开始的思路:
做一个如下的结构体:
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 0x7ffffff
using 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 0x7ffffff
using 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;
}