杭电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
- 杭电3339————最短路(SPFA)+ 01背包
- 最短路——SPFA
- 最短路——SPFA
- 三国志(最短路SPFA+01背包)
- hdu2544最短路——spfa
- hdu 2544——最短路 (spfa)
- 蓝桥杯(算法训练)——最短路 SPFA算法
- ACM-最短路(SPFA,Dijkstra,Floyd)之最短路——hdu2544
- hdu 3339 In Action spfa最短路+01背包
- hdu 3339 In Action(最短路spfa+01背包)
- 杭电 2544 最短路(dijkstra&&spfa)
- 杭电2544-最短路 -spfa算法求解最短路
- HDU 3339 In Action(最短路(Spfa)+01背包)
- 杭电1217————不像最短路的"最短路"
- 杭电3790————最短路问题
- 最短路模板——dijkstra,SPFA(邻接表实现)
- Islands Travel——SPFA求最短路
- 最短路 ( SPFA )——Ramzi ( Gym 101061 C )
- Jsonp跨域原理及实现
- asp.net获取网站绝对路径
- UIScorllView与UIPageControl
- Activity四种启动模式
- JSONObject和JSONArray区别及基本用法
- 杭电3339————最短路(SPFA)+ 01背包
- KVC、KVO
- Java---02---数据类型
- 民生信托-联华星河IEO经营性物业抵押贷款集合资金信托计划
- 在ubuntu下安装libpcap库 (解决方案很全)
- 由大学到至今的小作品(不定时更新)
- innodb的锁
- 杭电1004题
- MySQL_时间段维度统计