魔法宝石
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 254 Accepted Submission(s): 85
Problem Description
小s想要创造n种魔法宝石。小s可以用ai的魔力值创造一棵第i种魔法宝石,或是使用两个宝石合成另一种宝石(不消耗魔力值)。请你帮小s算出合成某种宝石的所需的最小花费。
Input
第一行为数据组数T(1≤T≤3)。
对于每组数据,首先一行为n,m(1≤n,m≤10^5)。分别表示魔法宝石种类数和合成魔法的数量。
之后一行n个数表示a1到an。(1≤ai≤10^9)。ai表示合成第i种宝石所需的魔力值。
之后m行,每行三个数a,b,c(1≤a,b,c≤n),表示一个第a种宝石和第b种宝石,可以合成一个第c种宝石。
对于每组数据,首先一行为n,m(1≤n,m≤10^5)。分别表示魔法宝石种类数和合成魔法的数量。
之后一行n个数表示a1到an。(1≤ai≤10^9)。ai表示合成第i种宝石所需的魔力值。
之后m行,每行三个数a,b,c(1≤a,b,c≤n),表示一个第a种宝石和第b种宝石,可以合成一个第c种宝石。
Output
每组数据输出一行n个数,其中第i个数表示合成第i种宝石的魔力值最小花费。
Sample Input
1 3 1 1 1 10 1 2 3
Sample Output
1 1 2
第一次看到这道题是17年山东省浪潮杯热身赛,当时第一次去参加省赛,激动,这个题没做出来,后来想了想热身赛。没事哒,不过后来又在杭电的一个比赛上看到了,确实该弄弄了,不能一直没进步。
思路,用spfa,记录下来每一个改变过的点,然后去搜索,搜索时找到这个点改变的起点(如果a+b=c),就找a,把所有从a开始的点都更新一遍,那些变动的点再次进入队列,从重复下去一定可以走到所有点的稳定状态----最小状态。
spfa
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn=1e5+5;
int t;
int n,m,len;
int mi[maxn];
int first[maxn];
bool ex[maxn];
queue <int> Q;
struct node{
int v1,v2,nxt;
}nn[maxn*2];
void spfa(){
while(!Q.empty()){
int st=Q.front();
Q.pop();
ex[st]=false;
for(int i=first[st];i!=-1;i=nn[i].nxt){
int v1=nn[i].v1,v2=nn[i].v2;
if(mi[v2] > mi[v1]+mi[st]){
mi[v2] = mi[v1]+mi[st];
if(!ex[v2]){
Q.push(v2);
ex[v2]=true;
}
}
}
}
}
void add_pi(int u,int v1,int v2){
nn[len].v1=v1;
nn[len].v2=v2;
nn[len].nxt=first[u];
first[u]=len++;
}
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
memset(first,-1,sizeof(first));
memset(ex,false,sizeof(ex));
while(!Q.empty())
Q.pop();
for(int i=1;i<=n;i++){
scanf("%d",mi+i);
}
int a,b,c;
len=0;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
add_pi(a,b,c);
add_pi(b,a,c);
if( mi[c] > mi[a] + mi[b] ){
mi[c] = mi[a] + mi[b];
if(!ex[c]){
Q.push(c);
ex[c]=true;
}
}
}
spfa();
printf("%d",mi[1]);
for(int i=2;i<=n;i++){
printf(" %d",mi[i]);
}
printf("\n");
}
return 0;
}
既然只要把所有点稳定状态找到就可以,那么 直接暴力就可以哒
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <queue>
#include <algorithm>
using namespace std;
const int MAXN=1e5+5;
int t;
int n,m;
int p[MAXN],mi[MAXN];
int a,b,c;
struct node{
int v1,v2,nxt;
}nn[MAXN];
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",p+i);
mi[i]=p[i];
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
nn[i].v1=a;
nn[i].v2=b;
nn[i].nxt=c;
}
int flag=0;
while(1){
for(int i=1;i<=m;i++){
int sum=mi[nn[i].v1]+mi[nn[i].v2];
if(sum < mi[nn[i].nxt]){
mi[nn[i].nxt]=sum;
flag=1;
}
}
if(!flag)
break ;
flag=0;
}
printf("%d",mi[1]);
for(int i=2;i<=n;i++){
printf(" %d",mi[i]);
}
printf("\n");
}
return 0;
}
暴力50次也可以过,估计比赛的时候很多人都是暴力过的吧
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <queue>
#include <algorithm>
using namespace std;
const int MAXN=1e5+5;
int t;
int n,m;
int p[MAXN],mi[MAXN];
int a,b,c;
struct node{
int v1,v2,nxt;
}nn[MAXN];
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",p+i);
mi[i]=p[i];
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
nn[i].v1=a;
nn[i].v2=b;
nn[i].nxt=c;
}
int o=50;
while(o--){
for(int i=1;i<=m;i++){
int sum=mi[nn[i].v1]+mi[nn[i].v2];
if(sum < mi[nn[i].nxt])
mi[nn[i].nxt]=sum;
}
}
printf("%d",mi[1]);
for(int i=2;i<=n;i++){
printf(" %d",mi[i]);
}
printf("\n");
}
return 0;
}