CodeForces 1245D Shichikuji and Power Grid

cf題面優化

解題思路

比勝過程中想了一個貪心——把全部城市按照自建代價排序,排在第一的城市確定自建,以後依次判斷排在後面的城市要自建仍是要鏈接前面的。這麼作WA13了(第一次忘開long longWA4)。spa

賽後看看題解,又參考了以前一樣WA13的 Artoriax的代碼,大概發現了這種作法的漏洞。假設自建代價是\(c_1<c_2<c_3\),能夠構造連邊的代價,使得在花費最小的鏈接方式中,連邊應該是1—3—2,我以前那樣的作法,1號城市自建之後,判斷2號城市要自建仍是要連1號城市,再判斷3號城市要自建仍是要連1號城市或者2號城市。.net

具體的hack數據以下——code

3
1 1
2 2
2 1
1 5 100
1 2 1

說簡單點大概就是,一、二、3自建代價是一、五、100,1到2連邊代價是5,1到3的連邊代價是2,2到3的連邊代價是3。最小代價答案是6,我那種方法跑出來是8。排序

我後來AC的思路大概是:首先假設每一個點都自建,那麼每一個點的代價就是自建代價。而後按照代價排序,用代價最小的點去更新後面那些點,若是能更新用電代價,就把那些點鏈接到當前點。而後進入下一輪循環,排除上一次代價最小的點,把剩下的點再次按照代價排序,而後用這些點中代價最小的去更新其餘的,以此類推。ip

官方題解還提供了一種更通常的想法:這題其實就是求一個最小生成樹,圖是這麼建的——首先全部點之間連邊,邊權就是鏈接代價,而後加一個0號點,全部點向0號點連邊,邊權是自建代價。這麼一想,我AC的思路就是毫無堆優化的、還不如線性直接找最小值的、很蠢的Prim了。get

源代碼

#include<cstdio>
#include<algorithm>
int n;
struct City{
    int id;
    long long x,y;
    long long cc,kk;
    bool self;
    int fa;
    bool operator < (const City & a)const{
        return cc<a.cc;
    }
}c[2005];
int main()
{
    // freopen("test.in","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        c[i].id=i;
        c[i].self=1;
        scanf("%lld%lld",&c[i].x,&c[i].y);
    }
    for(int i=1;i<=n;i++) scanf("%lld",&c[i].cc);
    for(int i=1;i<=n;i++) scanf("%lld",&c[i].kk);
    long long ans=0,selfnum=0;
    for(int i=1;i<=n;i++)
    {
        std::sort(c+i,c+1+n);//大概就是要隨時排序,每次找到最小的
        ans+=c[i].cc;
        if(c[i].self) selfnum++;
        for(int j=i+1;j<=n;j++)
        {
            long long cost=(c[i].kk+c[j].kk)*(std::abs(c[i].x-c[j].x)+std::abs(c[i].y-c[j].y));
            if(cost<c[j].cc)
            {
                c[j].cc=cost;
                c[j].self=0;//放棄自建
                c[j].fa=c[i].id;
            }
        }
    }
    printf("%lld\n%lld\n",ans,selfnum);
    for(int i=1;i<=n;i++)
        if(c[i].self) printf("%d ",c[i].id);
    printf("\n%lld\n",n-selfnum);
    for(int i=1;i<=n;i++)
        if(!c[i].self) printf("%d %d\n",c[i].id,c[i].fa);
    return 0;
}
相關文章
相關標籤/搜索