BZOJ1927星際競速

1927: [Sdoi2010]星際競速
Time Limit: 20 Sec Memory Limit: 259 MB
Submit: 1727 Solved: 1053
Description
10 年一度的銀河系賽車大賽又要開始了。作爲全銀河最盛大的活動之一, 奪得這個項目的冠軍無疑是很多人的夢想,來自傑森座 α星的悠悠也是其中之一。 賽車大賽的賽場由 N 顆行星和M條雙向星際航路構成,其中每顆行星都有 一個不同的引力值。大賽要求車手們從一顆與這 N 顆行星之間沒有任何航路的 天體出發,訪問這 N 顆行星每顆恰好一次,首先完成這一目標的人獲得勝利。 由於賽制非常開放,很多人駕駛着千奇百怪的自制賽車來參賽。這次悠悠駕 駛的賽車名爲超能電驢,這是一部凝聚了全銀河最尖端科技結晶的夢幻賽車。作 爲最高科技的產物,超能電驢有兩種移動模式:高速航行模式和能力爆發模式。 在高速航行模式下,超能電驢會展開反物質引擎,以數倍於光速的速度沿星際航 路高速航行。在能力爆發模式下,超能電驢脫離時空的束縛,使用超能力進行空 間跳躍——在經過一段時間的定位之後,它能瞬間移動到任意一個行星。 天不遂人願,在比賽的前一天,超能電驢在一場離子風暴中不幸受損,機能 出現了一些障礙:在使用高速航行模式的時候,只能由每個星球飛往引力比它大 的星球,否則賽車就會發生爆炸。 儘管心愛的賽車出了問題,但是悠悠仍然堅信自己可以取得勝利。他找到了 全銀河最聰明的賢者——你,請你爲他安排一條比賽的方案,使得他能夠用最少 的時間完成比賽。
Input
第一行是兩個正整數 N, M。 第二行 N 個數 A1~AN, 其中Ai表示使用能力爆發模式到達行星 i 所需的定位 時間。 接下來 M行,每行 3個正整數ui, vi, wi,表示在編號爲 ui和vi的行星之間存 在一條需要航行wi時間的星際航路。 輸入數據已經按引力值排序,也就是編號小的行星引力值一定小,且不會有 兩顆行星引力值相同。
Output
僅包含一個正整數,表示完成比賽所需的最少時間。
Sample Input
3 3
1 100 100
2 1 10
1 3 1
2 3 1
Sample Output
12
HINT
說明:先使用能力爆發模式到行星 1,花費時間 1。
然後切換到高速航行模式,航行到行星 2,花費時間10。
之後繼續航行到行星 3完成比賽,花費時間 1。
雖然看起來從行星 1到行星3再到行星 2更優,但我們卻不能那樣做,因爲
那會導致超能電驢爆炸。
對於 30%的數據 N≤20,M≤50;
對於 70%的數據 N≤200,M≤4000;
對於100%的數據N≤800, M≤15000。輸入數據中的任何數都不會超過106。
輸入數據保證任意兩顆行星之間至多存在一條航道,且不會存在某顆行星到
自己的航道。
Source
第一輪Day2
最小費用最大流+拆點建圖
把每個點拆成兩個點,分別爲入度點和出度點,因爲要每個點都走一遍,所以源點向入度點連邊,流量爲1,費用爲Ai,源點向出度點連邊,流量爲1,費用爲0,出度點向入度點連邊,且編號小的點連向大的,流量爲1,費用爲cost,入度點向匯點連邊,流量爲1,費用爲0.
附上本蒟蒻的代碼:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define inf 0x7fffffff
int n,m,T,h[100010],dis[100010],q[100010],head,tail,cnt=1,ans,sum;
bool mark[100010],vis[100010];
struct kx
{
    int to,next,v,c;
}edge[100010];

int read()
{
    int w=0,f=1; char ch=getchar();
    while (ch<'0' || ch>'9')
      {
        if (ch=='-') f=-1;
        ch=getchar();
      }
    while (ch>='0' && ch<='9')
      w=w*10+ch-'0',ch=getchar();
    return w*f;
}

void add(int u,int v,int w,int cost)
{
    cnt++,edge[cnt].next=h[u],h[u]=cnt,edge[cnt].to=v,edge[cnt].v=w,edge[cnt].c=cost;
    cnt++,edge[cnt].next=h[v],h[v]=cnt,edge[cnt].to=u,edge[cnt].v=0,edge[cnt].c=-cost;
}

bool spfa()
{
    int i,now;
    memset(vis,false,sizeof(vis));
    for (i=0;i<=T;i++) dis[i]=inf;
    head=0,tail=1,q[0]=T,vis[T]=true,dis[T]=0;
    while (head<tail)
      {
        now=q[head],head++,vis[now]=false;
        for (i=h[now];i;i=edge[i].next)
          if (edge[i^1].v && dis[now]-edge[i].c<dis[edge[i].to])
            {
              dis[edge[i].to]=dis[now]-edge[i].c;
              if (!vis[edge[i].to])
                vis[edge[i].to]=true,q[tail++]=edge[i].to;
            }
      }
    return dis[0]!=inf;
}

int dfs(int x,int f)
{
    int w,used=0,i;
    mark[x]=true;
    if (x==T) return f;
    for (i=h[x];i;i=edge[i].next)
      if (dis[edge[i].to]==dis[x]-edge[i].c && edge[i].v && !mark[edge[i].to])
        {
            w=f-used,w=dfs(edge[i].to,min(w,edge[i].v)),ans+=w*edge[i].c;
            edge[i].v-=w,edge[i^1].v+=w,used+=w;
            if (used==f) return f;
        }
    return used;
}

int main()
{
    int i,x,y,z;
    n=read(),m=read();
    T=2*n+1;
    for (i=1;i<=n;i++) x=read(),add(0,i,1,0),add(0,i+n,1,x),add(i+n,T,1,0);
    for (i=1;i<=m;i++)
      {
        x=read(),y=read(),z=read();
        if (x>y) swap(x,y);
        add(x,y+n,1,z);
      }
    while (spfa())
      {
        mark[T]=true;
        while (mark[T])
          {
            memset(mark,false,sizeof(mark));
            sum+=dfs(0,inf);
          }
      }
    printf("%d",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章