3339 In Action (最短路+01揹包)
阿新 • • 發佈:2018-12-16
簡述題意:
給出N個供電站編號從1~N,然後給出M條邊:並且給出這N個供電站的電量。每輛坦克從基地出發去攻擊供電站,並且每輛坦克只能攻擊一個供電站,求要使的破壞總電量的一半以上,求這些坦克要走的最短距離。
難度:NOIP
演算法:首先,從基地跑一次最短路,求出到所有供電站的距離,接下來就是01揹包了!
所有供電站的電量總和為->揹包容量
每個供電站為->揹包中的物品
每個供電站的電量為->揹包中物品的代價
基地到每個供電站的距離為->揹包中物品的價值
所以,記得清陣列,判無解。
程式碼如下:
#include <bits/stdc++.h> #define ll long long #define N 10005 using namespace std; struct node { int next; int to; int val; }edg[N<<1]; int hea[N],cnt=1; int vis[N],dis[N]; void init() { memset(hea,-1,sizeof(hea)); memset(vis,0,sizeof(vis)); cnt=1; } void add(int u,int v,int w) { edg[cnt].next=hea[u]; edg[cnt].to=v; edg[cnt].val=w; hea[u]=cnt++; } struct no { int d; int po; }; bool operator < (no x,no y) { return x.d>y.d; } void dijkstra(int rt) { memset(dis,0x3f3f3f3f,sizeof(dis)); priority_queue<no>Q; no tem; tem.d=0; tem.po=rt; dis[rt]=0; Q.push(tem); while(!Q.empty()) { no tt=Q.top(); Q.pop(); int u=tt.po; if(vis[u]) continue; vis[u]=1; for(int i = hea[u];i != -1;i=edg[i].next) { int to=edg[i].to; if(dis[to]>dis[u]+edg[i].val) { dis[to]=dis[u]+edg[i].val; no point; point.po=to; point.d=dis[to]; Q.push(point); } } } } int aa[150]; int dp[N]; int main() { int T; scanf("%d",&T); while(T--) { int n,m; scanf("%d%d",&n,&m); init(); for(int i = 1;i <= m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); add(a+1,b+1,c),add(b+1,a+1,c); } int sum=0; for(int i = 1;i <= n;i++) { scanf("%d",&aa[i]); sum+=aa[i]; } dijkstra(1); int ans=0x3f3f3f3f; memset(dp,0x3f3f3f3f,sizeof(dp)); dp[0] = 0; for(int i = 1;i <= n;i++) { for(int j = sum;j >= aa[i];j--) { dp[j]=min(dp[j],dp[j-aa[i]]+dis[i+1]); } } for(int i = sum/2+1;i <= sum;i++) { ans=min(ans,dp[i]); } if(ans==0x3f3f3f3f) puts("impossible"); else printf("%d\n",ans); } return 0 ; }