1. 程式人生 > >HAUT 1262 魔法寶石(spfa)(河南工業大學2017校賽)

HAUT 1262 魔法寶石(spfa)(河南工業大學2017校賽)

魔法寶石

題目描述

小s想要創造n種魔法寶石。小s可以用ai的魔力值創造一棵第i種魔法寶石,或是使用兩個寶石合成另一種寶石(不消耗魔力值)。請你幫小s算出合成某種寶石的所需的最小花費。

輸入

第一行為資料組數T(1≤T≤3)。
對於每組資料,首先一行為n,m(1≤n,m≤10^5)。分別表示魔法寶石種類數和合成魔法的數量。
之後一行n個數表示a1到an。(1≤ai≤10^9)。a_i表示合成第i種寶石所需的魔力值。
之後n行,每行三個數a,b,c(1≤a,b,c≤n),表示一個第a種寶石和第b種寶石,可以合成一個第c種寶石。

輸出

每組資料輸出一行n個數,其中第i個數表示合成第i種寶石的魔力值最小花費。

樣例輸入

1
3 1
1 1 10
1 2 3
樣例輸出

1 1 2

思路:類似於雙向建邊,只不過是在權值處變化了一點,直接spfa即可

程式碼:

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;

#define maxn 500010
struct node
{
    int v1,v2,next;
}G[maxn*2];
int n,m,len;
int first[maxn],d[maxn];
bool inq[maxn];
queue<int
>Q; void spfa() { while(!Q.empty()) { int st=Q.front(); Q.pop(); inq[st]=false; for(int i=first[st];i!=-1;i=G[i].next) { int v1=G[i].v1,v2=G[i].v2; if(d[v2]>d[v1]+d[st]) { d[v2]=d[v1]+d[st]; if
(!inq[v2]) { Q.push(v2); inq[v2]=true; } } } } } void add_egde(int u,int v1,int v2) { G[len].v1=v1,G[len].v2=v2,G[len].next=first[u]; first[u]=len++; } int main() { int t; scanf("%d",&t); while(t--) { memset(first,-1,sizeof(first)); memset(inq,false,sizeof(inq)); while(!Q.empty()) Q.pop(); scanf("%d%d",&n,&m); for(int i=1; i<=n; ++i) scanf("%d",&d[i]); len=0; int a,b,c; for(int i=1; i<=m; ++i) { scanf("%d%d%d",&a,&b,&c); add_egde(a,b,c); add_egde(b,a,c); if(d[c]>d[a]+d[b]) { d[c]=d[a]+d[b]; if(!inq[c]) { Q.push(c); inq[c]=true; } } } spfa(); for(int i=1;i<n;++i) printf("%d ",d[i]); printf("%d\n",d[n]); } return 0; }

結果,比賽時讓我暴力水過。。。

程式碼:

#include<stdio.h>

#define maxn 100010
int d[maxn],a[maxn],b[maxn],c[maxn];
int n,m;


int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i)
            scanf("%d",&d[i]);
        for(int i=1;i<=m;++i)
        {
            scanf("%d%d%d",&a[i],&b[i],&c[i]);
            if(d[c[i]]>d[a[i]]+d[b[i]])
                d[c[i]]=d[a[i]]+d[b[i]];
        }
        int flag=1;
        while(flag)
        {
            flag=0;
            for(int i=1;i<=m;++i)
            {
                if(d[c[i]]>d[a[i]]+d[b[i]])
                {
                    flag=1;
                    d[c[i]]=d[a[i]]+d[b[i]];
                }
            }
        }
        for(int i=1;i<n;++i)
            printf("%d ",d[i]);
        printf("%d\n",d[n]);
    }
    return 0;
}



總結:有一點變形的最短路比賽時還是想不到該怎樣去寫,,,我想主要還是對鬆弛的套路太固定了,還是要多深思,多學點套路!