[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 }
View Code

 

posted @ 2019-08-16 11:03  PYWBKTDA  阅读(167)  评论(0编辑  收藏  举报