【HDU5545 2015 CCPC 南阳国赛F】【差分约束思想 费用流思想】The Battle of Guandu 官渡之战 重要战场人数多 士兵流向转化问题为最短路spfa+dijkstra双写
2015-11-04 16:13
246 查看
#include<stdio.h> #include<string.h> #include<ctype.h> #include<math.h> #include<iostream> #include<string> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);} #define MS(x,y) memset(x,y,sizeof(x)) #define MC(x,y) memcpy(x,y,sizeof(x)) #define MP(x,y) make_pair(x,y) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;} template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;} const int N=1e5+10,M=1e5+10,Z=1e9+7,ms63=1061109567; int casenum,casei; int n,m; int x ,y ,cc ; int ww[M]; int first[M],id; int w ,c ,nxt ; LL f[M]; bool e[M]; void ins(int x,int y,int z) { id++; w[id]=y; c[id]=z; nxt[id]=first[x]; first[x]=id; } struct node { int x;LL v; node(){} node(int x_,LL v_){x=x_;v=v_;} bool operator < (const node& b)const {return v>b.v;} }; priority_queue<node>q; void inq(int x,LL v) { if(v>=f[x])return; f[x]=v; q.push(node(x,v)); } LL dijkstra() { for(int i=1;i<=n;i++) { ins(y[i],x[i],cc[i]); if(ww[y[i]]==0)inq(y[i],0); } while(!q.empty()) { int x=q.top().x;q.pop(); if(e[x])continue;e[x]=1; for(int z=first[x];z;z=nxt[z])inq(w[z],f[x]+c[z]); } LL ans=0; for(int i=1;i<=m;i++) { if(ww[i]==2) { if(f[i]==1e12)return -1; ans+=f[i]; } } return ans; } const int L=1e6; int Q[L],h,t; void inQ(int x,LL v) { if(v>=f[x])return; f[x]=v; if(e[x])return; e[x]=1; Q[t++]=x; } LL spfa() { h=t=0; for(int i=1;i<=n;i++) { ins(y[i],x[i],cc[i]); if(ww[y[i]]==0)inQ(y[i],0); } while(h<t) { int x=Q[h++];e[x]=0; for(int z=first[x];z;z=nxt[z])inQ(w[z],f[x]+c[z]); } LL ans=0; for(int i=1;i<=m;i++) { if(ww[i]==2) { if(f[i]==1e12)return -1; ans+=f[i]; } } return ans; } int main() { scanf("%d",&casenum); for(casei=1;casei<=casenum;casei++) { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { first[i]=0; f[i]=1e12; e[i]=0; }id=0; for(int i=1;i<=n;i++)scanf("%d",&x[i]); for(int i=1;i<=n;i++)scanf("%d",&y[i]); for(int i=1;i<=n;i++)scanf("%d",&cc[i]); for(int i=1;i<=m;i++)scanf("%d",&ww[i]); //首先是dijkstra写法 //printf("Case #%d: %lld\n",casei,dijkstra()); //然后是SPFA写法 printf("Case #%d: %lld\n",casei,spfa()); } return 0; } /* 【trick&&吐槽】 有1e5个点,边权也为1e5,是可能爆int的。 【题意】 有T(30)组数据。 对于每组数据有n(1e5)个村庄,m(1e5)个战场 对于村庄i,曹操可以选择支付c[i]*num元,(0<=c[i]<=1e5) 使得这个村庄派出num个士兵,在战场x[i]为曹操作战,在战场y[i]为袁绍作战。(1<=x[i],y[i]<=m) 对于每个战场,都有个战略价值(0,1,2)。 在战略价值为2的战场,曹操在该战场的士兵数必须严格比袁绍多 在战略价值为1的战场,曹操在该战场的士兵数必须不能比袁绍少(按照贪心原则,实际一定会相等) 在战略价值为0的战场,曹操在该战场的士兵数无所谓(按照贪心原则,实际一定会为0) 让你输出保障上述条件曹操至少需要花费的金钱。 如果无法保障这个条件,则输出-1。 【类型】 差分约束思想 网络流思想 最短路。 【分析】 首先有一个很显然的贪心—— 如果一个战场的战略价值为2,那么在这个战场,恰有:曹兵-袁兵=1 如果一个战场的战略价值为1,那么在这个战场,恰有:曹兵=袁兵=0 这题我们可以从村庄向两个战场连边。 但是——如何更加简单地设置关系呢? 为何不考虑直接从曹战场向袁战场连边呢? 这题设计到分配,尽管数据巨大不能用网络流做,我们还是可以考虑先简化数据规模,引入思想。 我们对于每个村庄所提供的(x,y,z),从曹战场x向袁战场y连接一条流量无穷,费用为z的边。 然后,我们有一个关键性的问题就是,如何保证题目的要求呢? 首先我们简化问题,只去考虑合法性。 对于所有战略价值为2的战场,如果从这个样的点ST出发,沿着图,能够达到任意一个战略价值为0的点。 那说明,这个战略价值为2的战场,可以使得其上的曹兵比袁兵多。 为什么能说明这个呢? 很显然,我们对于一条边,使得ST的曹兵+1,下一个点的袁兵+1。 但是这样,对于下一个点是有影响的。 如果下个点重要度为0,显然这样已经可以了。 如果下个点重要度为1,我们还要继续把这1个人转移出去,一直转移到重要度为0的点上即可。 如果下个点重要度为2,我们依然一定要把这1个人转移出去。而只要转移出去了,下个点实际上其实并没有受到影响。 于是,我们枚举所有重要度为2的点,每个点沿着这个图转移一个人到重要度为0的战场上,这道题就可以AC了。 体现在网络流上,就是: [超级源点->重要度为2的点,流量为1,费用为0] [曹战场->袁战场,流量无限,费用为人的雇佣成本] [重要度为0的点->超级汇点,流量无限,费用为0] 跑一个最小费用最大流,如果最大流=重要度为2的点数,那么这个最小费用就是答案了。 只是时间复杂度不允许我们跑最小费用最大流。 然而我们发现,基于这道题的特殊性,其实直接求: 枚举每个重要度为2的点, 对于每个这样的点,求它到重要度为0的点中距离最近的那个的距离。 然后这些距离求和即可。 但是这样是多源最短路。 然而我们发现,只要把边逆过来,初始化所有重要度为0的点为起点,都归为ZERO,求最短路。 然后累加所有重要度为2的点的到 ZERO的最短路即可。 【时间复杂度&&优化】 dijkstra O(nlogn) SPFA O(kn) */
相关文章推荐
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- 基于C++实现的各种内部排序算法汇总
- C++线性时间的排序算法分析
- C++实现汉诺塔算法经典实例
- PHP实现克鲁斯卡尔算法实例解析
- C#获取关键字附近文字算法实例