Description
因为下雨的关系,小朋友被困在综一了,W先生知道后,立即前往营救,一个N个点的图,一共M条边,边是双向的,但是因为下雨和打雷的关系,每个端点上都有雷震子镇守,想通过该点,必须被雷震子雷劈,每个雷震子都有一个雷劈伤害值,W先生很幸运,他有F张IP(挨劈)卡,一张IP卡可以抵消一次雷劈伤害,但是有个要求,不能在X和Y点都使用IP卡,也就是在X,Y两点中的最多使用一张IP卡,W先生要从S 点前往 T点,又想自己的雷劈伤害值总和最小,现在W先生问你,他的最低的雷劈伤害值总和是多少。
Input
多组case,以eof结尾
第一行 N表示点的数量(N<=200),M表示边的数量(M<=N*N)
接下来M行,每行两个数 : u ,v 表示 u点和v点是连接的。
接下来 一行 N 个数 : 第i个数 表示 i号点 雷震子的雷劈伤害值为 ci,1<=ci<=1000。
接下来 一行 :S,T (1<=S,T<=N)
接下来 一行 :X , Y, F (1<=X<Y<=N, F<=50)
Output
每个case输出一行,最低的雷劈伤害总和是多少。(当无法到达T时输出-1)。
Sample Input
5 41 22 33 44 51 5 4 9 11 52 4 2
Sample Output
7
最初看起来是一道最短路,仔细想了一想,因为是点上有权值而不是每条边有权值,
所以用优先队列的bfs做出来了。队列的元素是结构体,存当前节点和走到当前节点所用的权值。
先把起点放入队列,把与起点相连的所有点全部加上权值放入队列。
由于每次队列顶都是权值最小的,所以该点能走到的节点一定不会有其他点能走到且比当前点更短。
因为这个所以我们可以bfs。
每次加入一个节点,都用一个数组把当前节点的前驱记录下来。
最后从终点遍历,记录走过路径所经过的节点,
把最大的F个点去掉(注意X,Y的处理),其余点的权值之和就是所求的答案。
#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=205;
bool ok[maxn][maxn],OK[maxn];
int a[maxn],c[maxn];
int N,M,S,T,X,Y,F;
struct xx
{
int i,n;
friend bool operator < (xx a,xx b)
{
return a.n>b.n;
}
};
bool cmp(int i,int j)
{
return a[i]>a[j];
}
int main()
{
while(cin>>N>>M)
{
int i,j,ans=0;
bool ok1=1;
priority_queue<xx>bfs;
memset(ok,0,sizeof(ok));
memset(a,0,sizeof(a));
memset(c,0,sizeof(c));
memset(OK,0,sizeof(OK));
while(M--)
{
int u,v;
cin>>u>>v;
ok[u][v]=ok[v][u]=1;
}
for(i=1;i<=N;++i)
cin>>a[i];
cin>>S>>T>>X>>Y>>F;
bfs.push((xx){S,0});
while(!bfs.empty())
{
int i=bfs.top().i,n=bfs.top().n;
bfs.pop();
for(int k=1;k<=N;++k)
if(ok[i][k]&&!OK[k])
{
OK[k]=1;
bfs.push((xx){k,n+a[k]});
c[k]=i;
}
}
i=T;
int o=0;
int XX[maxn];
XX[o++]=T;
while(i!=S)
{
XX[o++]=c[i];
i=c[i];
}
sort(XX,XX+o,cmp);
for(i=0;i<o;++i)
{
if((XX[i]==X||XX[i]==Y)&&ok1)
{
ok1=0; F--;
}
else if((XX[i]==X||XX[i]==Y)&&ok1==0)
{
ans+=a[XX[i]];
}
else if(F)
{
F--;
}
else ans+=a[XX[i]];
}
cout<<ans<<endl;
}
return 0;
}
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=205;
bool ok[maxn][maxn],OK[maxn];
int a[maxn],c[maxn];
int N,M,S,T,X,Y,F;
struct xx
{
int i,n;
friend bool operator < (xx a,xx b)
{
return a.n>b.n;
}
};
bool cmp(int i,int j)
{
return a[i]>a[j];
}
int main()
{
while(cin>>N>>M)
{
int i,j,ans=0;
bool ok1=1;
priority_queue<xx>bfs;
memset(ok,0,sizeof(ok));
memset(a,0,sizeof(a));
memset(c,0,sizeof(c));
memset(OK,0,sizeof(OK));
while(M--)
{
int u,v;
cin>>u>>v;
ok[u][v]=ok[v][u]=1;
}
for(i=1;i<=N;++i)
cin>>a[i];
cin>>S>>T>>X>>Y>>F;
bfs.push((xx){S,0});
while(!bfs.empty())
{
int i=bfs.top().i,n=bfs.top().n;
bfs.pop();
for(int k=1;k<=N;++k)
if(ok[i][k]&&!OK[k])
{
OK[k]=1;
bfs.push((xx){k,n+a[k]});
c[k]=i;
}
}
i=T;
int o=0;
int XX[maxn];
XX[o++]=T;
while(i!=S)
{
XX[o++]=c[i];
i=c[i];
}
sort(XX,XX+o,cmp);
for(i=0;i<o;++i)
{
if((XX[i]==X||XX[i]==Y)&&ok1)
{
ok1=0; F--;
}
else if((XX[i]==X||XX[i]==Y)&&ok1==0)
{
ans+=a[XX[i]];
}
else if(F)
{
F--;
}
else ans+=a[XX[i]];
}
cout<<ans<<endl;
}
return 0;
}
本文介绍了一个关于寻找从起点到终点经历最小雷劈伤害总和的算法问题。该问题在一个带有点权的图中进行,需考虑特殊点限制及使用IP卡抵消伤害等条件。采用优先队列实现广度优先搜索解决。

被折叠的 条评论
为什么被折叠?



