2019ICPC(南昌) - Fire-Fighting Hero(最短路+思维)
題目鏈接:點擊查看
題目大意:有一個由n個點,m條邊組成的無環無向圖,題目保證是連通圖,現在每個點代表一個著火點,有一個消防英雄和k個消防隊伍比賽救火,他們的具體位置輸入時會給出,誰的分數低誰就獲勝,分數的定義如下:
消防英雄:到每個著火點的最短路中的最大值除以題目中給出的C
消防隊伍:從k個隊伍中選擇最優的一個消防隊伍(即下半句話中描述的分數最小的隊伍),也是取到每個著火點的最短路中的最大值
如果消防英雄獲勝,輸出消防英雄的原分數,如果消防隊伍獲勝,輸出消防隊伍的原分數,如果平局,算是消防英雄獲勝
題目分析:這個題超級坑。。一點是比賽時的答疑區,出題老師把題意說錯了,雖然并不影響我們隊做不出這個題orz,其次就是建邊不好想,想到了就是簡單的兩邊迪杰斯特拉,想不到就是暴力弗洛伊德,但我們暴力走的給的回饋卻是WA,有點自閉。。說一下正解吧,就是將k個點之間建邊,邊權為0,這樣就相當于將k個點視為一個點,然后對一個點跑一邊迪杰斯特拉,就能直接求出來k個點中到達某一點的最短路了,最后維護一下最大值即可,簡單易懂。。但我們想不出來,利用這個思想也可以直接維護一個距離數組dis[N],然后也是跑一遍迪杰斯特拉,只不過這次初始化的時候將k個點都預先扔進優先隊列中,并將dis[i]初始化為0,扔進去讓他自己跑答案去吧。。有點bfs搜索的思想,不過主體還是將k個點視為一個點,學到了,真的學到了。
有個小細節就是,最后為了避免出現浮點數,消防英雄除以C,變成消防隊伍乘以C即可,爆不了int
上代碼吧,兩個代碼大同小異:
令第一個隊伍為中心點,與其他隊伍建邊權為0的邊:
#include<iostream> #include<string> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<cstdio> #include<queue> using namespace std; typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e3+100;int n,m,s,k,c;int team[N];int maze[N][N];struct Node {int id,dis;Node(int ID,int DIS){id=ID;dis=DIS;}bool operator<(const Node &a)const{return dis>a.dis;} };priority_queue<Node>q;int d[N];bool vis[N];void Dijkstra(int s) {while(!q.empty())q.pop();for(int i=1;i<=n;i++){d[i]=inf;vis[i]=false;}d[s]=0;q.push(Node(s,0));while(!q.empty()){Node temp=q.top();q.pop();int u=temp.id;int w=temp.dis;if(vis[u])continue;vis[u]=true;for(int i=1;i<=n;i++){if(d[i]>d[u]+maze[u][i]){d[i]=d[u]+maze[u][i];q.push(Node(i,d[i]));}}} } int main() {int w;cin>>w;while(w--){scanf("%d%d%d%d%d",&n,&m,&s,&k,&c);for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)maze[i][j]=i==j?0:inf;for(int i=1;i<=k;i++)scanf("%d",team+i);while(m--){int u,v,w;scanf("%d%d%d",&u,&v,&w);if(maze[u][v]>w)maze[u][v]=maze[v][u]=w;}Dijkstra(s);int ans=0;for(int i=1;i<=n;i++)ans=max(ans,d[i]);int ss=team[1];for(int i=1;i<=k;i++)maze[ss][team[i]]=maze[team[i]][ss]=0; Dijkstra(ss);int anss=0;for(int i=1;i<=n;i++)anss=max(anss,d[i]);if(ans<=anss*c)printf("%d\n",ans);else if(ans>anss*c)printf("%d\n",anss);} return 0; }初始化時將K個點都扔進優先隊列中:
#include<iostream> #include<string> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<cstdio> #include<queue> using namespace std; typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e3+100;int n,m,s,k,c;int team[N];int maze[N][N];struct Node {int id,dis;Node(int ID,int DIS){id=ID;dis=DIS;}bool operator<(const Node &a)const{return dis>a.dis;} };priority_queue<Node>q;int d[N];bool vis[N];void Dijkstra() {while(!q.empty()){Node temp=q.top();q.pop();int u=temp.id;int w=temp.dis;if(vis[u])continue;vis[u]=true;for(int i=1;i<=n;i++){if(d[i]>d[u]+maze[u][i]){d[i]=d[u]+maze[u][i];q.push(Node(i,d[i]));}}} } void init() {while(!q.empty())q.pop();for(int i=1;i<=n;i++){d[i]=inf;vis[i]=false;} }int main() {int w;cin>>w;while(w--){scanf("%d%d%d%d%d",&n,&m,&s,&k,&c);for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)maze[i][j]=i==j?0:inf;for(int i=1;i<=k;i++)scanf("%d",team+i);while(m--){int u,v,w;scanf("%d%d%d",&u,&v,&w);if(maze[u][v]>w)maze[u][v]=maze[v][u]=w;}init();d[s]=0;q.push(Node(s,0));Dijkstra();int ans=0;for(int i=1;i<=n;i++)ans=max(ans,d[i]);init();for(int i=1;i<=k;i++){d[team[i]]=0;q.push(Node(team[i],0));}Dijkstra();int anss=0;for(int i=1;i<=n;i++)anss=max(anss,d[i]);if(ans<=anss*c)printf("%d\n",ans);else if(ans>anss*c)printf("%d\n",anss);} return 0; }?
總結
以上是生活随笔為你收集整理的2019ICPC(南昌) - Fire-Fighting Hero(最短路+思维)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2019ICPC(南昌) - The N
- 下一篇: 2019ICPC(南昌) - Magic