COGS 2091. Asm.Def的打击序列
★★★ 输入文件:asm_lis.in
输出文件:asm_lis.out
简单对比
时间限制:4 s 内存限制:256 MB
【题目描述】
白色圆柱形的“蓝翔”号在虚空中逐渐变大,一声沉闷的撞击后停住不动。空气阀开始“嘶嘶”作响。
Asm.Def钻出舱门,杜舰长热情地向他伸出右手,“来者可是Asm.Def?”
“正是。”他趁着握手将U盘递给舰长,“这里是所有目标位置,方教授说控制太空就靠你了,否则咱的通信卫星就是一坨废物。”
“没问题,就用这个,保证让它们灰飞烟灭。”杜舰长调出全息图像,是个细长的针状物体。
“阿姆斯特朗回旋加速喷气式阿姆斯特朗动能弹,”舰长介绍道,“本来想用强相互作用力材料,可惜没弄成,但撞击结构关键点,普通合金也够了。”
“雷达数据有误怎么办?靠信仰?”Asm.Def质疑。
“放心吧,我每个月都替它交党费。”
Asm.Def需要帮忙制定打击序列。我们可以把所有目标看做一个N个点,M条边的边带权有向图,每个点都是一个目标。
有两种手段:动能弹和激光。
Asm.Def可以发射若干枚(也可以是零枚)动能弹。每一枚动能弹会沿图中一条简单路径或简单环飞行:
简单路径形如p1->p2->…->pk,其中p1~pk互不相等,且(p1,p2),(p2,p3)…(pk-1,pk)均为图中的有向边。这时目标p2,p3,…,pk会被摧毁,但p1未被摧毁(因为动能弹在p1处尚未充分加速)。
简单环形如p1->p2->…->pk->p1,其中p1~pk互不相等,且(p1,p2),(p2,p3)…(pk,p1)均为图中的有向边。这时目标p1,p2,…,pk都会被摧毁。
一个目标至多出现在一枚动能弹的路径上(即所有动能弹的路径互不相交,包括简单路径中的p1),因为目标碎片十分危险。
动能弹的费用是它飞行路径的边权之和。
除了动能弹,也可以用激光摧毁一个目标,费用是C。
Asm.Def希望算出摧毁所有目标的最小费用。
【输入格式】
第1行3个整数:N,M,C。
接下来M行,每行3个整数s,t,v,代表有一条s->t的有向边,边权为v。
【输出格式】
1行1个整数,即摧毁所有目标的最小费用。
【样例输入1】
4 3 10 1 2 2 2 3 2 3 1 2
【样例输出1】
16
【样例输入2】
6 5 5 1 3 2 2 3 2 3 4 2 4 5 2 4 6 2
【样例输出2】
21
【提示】
样例1:一枚动能弹路径为1->2->3,花费6,用激光摧毁4,花费10.
样例2:一枚动能弹路径为1->3->4->5,花费6,用激光摧毁1,2,6,花费15.
对于40%的数据,2<=N<=5,1<=M<=10.
对于100%的数据,2<=N<=250,1<=M<=30000;s≠t;1<=s,t<=N;1<=v,c<=10000.
两对城市间可能有多条路径,但不会有自环。
【来源】
在此键入。
费用流
#include <cstdio> #include <queue> #define N 30005 #define inf 0x3f3f3f3f using namespace std; bool vis[N]; int n,m,c,S,T,cnt=1,to[N<<1],fa[N],DIS[N],came[N],flow[N<<1],val[N<<1],head[N],nextt[N<<1]; void ins(int u,int v,int f,int w) { nextt[++cnt]=head[u];to[cnt]=v;flow[cnt]=f;val[cnt]=w;head[u]=cnt; nextt[++cnt]=head[v];to[cnt]=u;flow[cnt]=0;val[cnt]=-w;head[v]=cnt; } inline int min(int a,int b) {return a>b?b:a;} bool spfa() { for(int i=S;i<=T;++i) DIS[i]=inf,came[i]=inf,vis[i]=false; DIS[S]=0; queue<int>q; q.push(S); for(int u;!q.empty();) { u=q.front(); q.pop(); vis[u]=false; for(int i=head[u];i;i=nextt[i]) { int v=to[i]; if(DIS[v]>DIS[u]+val[i]&&flow[i]) { DIS[v]=DIS[u]+val[i]; fa[v]=i; came[v]=min(came[u],flow[i]); if(!vis[v]) {vis[v]=true;q.push(v);} } } } return DIS[T]!=inf; } int main(int argc,char *argv[]) { freopen("asm_lis.in","r",stdin); freopen("asm_lis.out","w",stdout); scanf("%d%d%d",&n,&m,&c); S=0,T=n<<1|1; int ans=0,left=n; for(int s,t,v;m--;) { scanf("%d%d%d",&s,&t,&v); if(v>=c) continue; ins(s,t+n,1,v); } for(int i=1;i<=n;++i) { ins(S,i,1,0); ins(S,i+n,1,c); ins(i+n,T,1,0); } while(spfa()) { int t=came[T]; for(int i=T;i!=S&&i;i=to[fa[i]^1]) { flow[fa[i]]-=t; flow[fa[i]^1]+=t; } ans+=t*DIS[T]; } printf("%d\n",ans); return 0; }