[bzoj1927]星际竞速
考虑没有爆发,那么相当于是带权最小不可交路径覆盖,由于只能从编号小的到编号大的,因此一定是DAG,而DAG的最小路径覆盖可以拆点并跑最大流,那么带权的只需要跑费用流即可(S向i连(1,0)的边,i’向T连(1,0)的边,i向j’连(1,t)的边,其中i->j有时间为t的边)。
考虑爆发操作,相当于让任意两点之间都能够新增一条边,但这样就不是DAG了,可以直接从S连向i’(1,ai)的边(ai表示i爆发的代价)即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 2005 4 struct ji{ 5 int nex,to,len,cost; 6 }edge[N*20]; 7 queue<int>q; 8 int E,n,m,t,x,y,head[N],d[N],vis[N],from[N]; 9 void add(int x,int y,int z,int w){ 10 edge[E].nex=head[x]; 11 edge[E].to=y; 12 edge[E].len=z; 13 edge[E].cost=w; 14 head[x]=E++; 15 if (E&1)add(y,x,0,-w); 16 } 17 bool spfa(){ 18 memset(d,0x3f,sizeof(d)); 19 memset(vis,0,sizeof(vis)); 20 q.push(0); 21 d[0]=0; 22 while (!q.empty()){ 23 int k=q.front(); 24 q.pop(); 25 vis[k]=0; 26 for(int i=head[k];i!=-1;i=edge[i].nex){ 27 int v=edge[i].to; 28 if ((edge[i].len)&&(d[v]>d[k]+edge[i].cost)){ 29 d[v]=d[k]+edge[i].cost; 30 from[v]=i; 31 if (!vis[v]){ 32 vis[v]=1; 33 q.push(v); 34 } 35 } 36 } 37 } 38 return d[t]<0x3f3f3f3f; 39 } 40 int dinic(){ 41 int ans=0; 42 while (spfa()){ 43 ans+=d[t]; 44 for(int i=t;i;i=edge[from[i]^1].to){ 45 edge[from[i]].len--; 46 edge[from[i]^1].len++; 47 } 48 } 49 return ans; 50 } 51 int main(){ 52 scanf("%d%d",&n,&m); 53 memset(head,-1,sizeof(head)); 54 for(int i=1;i<=n;i++){ 55 scanf("%d",&t); 56 add(0,i,1,0); 57 add(0,i+n,1,t); 58 add(i+n,2*n+1,1,0); 59 } 60 for(int i=1;i<=m;i++){ 61 scanf("%d%d%d",&x,&y,&t); 62 if (x>y)swap(x,y); 63 add(x,y+n,1,t); 64 } 65 t=2*n+1; 66 printf("%d",dinic()); 67 }