题目描述 Description
PP 特别喜欢玩即时战略类游戏,但他觉得那些游戏都有美中不足的地方。灾害总不降临道路,而只降临城市,而且道路不能被占领,没有保护粮草的真实性。于是他就研发了《新三国争霸》。
在这款游戏中,加入灾害对道路的影响(也就是一旦道路W[i,j]受到了灾害的影响,那么在一定时间内,这条路将不能通过)和道路的占领权(对于一条道路W[i,j],至少需要K[i,j]个士兵才能守住)。
PP可真是高手,不一会,就攻下了N-1座城市,加上原来的就有N座城市了,但他忽略了一点……那就是防守同样重要,不过现在还来的及。因为才打完仗所以很多城市都需要建设,PP估算了一下,大概需要T天。他现在无暇分身进攻了,只好在这T天内好好的搞建设了。所以他秒要派士兵占领一些道路,以确保任何两个城市之间都有路(不然敌人就要分而攻之了,是很危险的)。士兵可不是白干活的,每个士兵每天都要吃掉V的军粮。因为有灾害,所以方案可能有变化(每改变一次就需要K的军粮,初始方案也需要K的军粮)。
因为游戏是PP编的,所以他知道什么时候有灾害。PP可是一个很节约的人,他希望这T天在道路的防守上花最少的军粮。
N<=300,M<=5000 ,T<=50;
输入描述 Input Description
第一行有5个整数N,M,T,V,K。N表示有城市数,M表示道路数,T表示需要修养的天数,V表示每个士兵每天吃掉的军粮数,K表示修改一次花掉的军粮数。
以下M行,每行3个数A,B,C。表示A与B有一条路(路是双向的)需要C个士兵才能守住。
第M+2行是一个数P,表示有P个灾害。
以下P行,每行4个数,X,Y,T1,T2。表示X到Y的这条路,在T1到T2这几天都会受灾害。
输出描述 Output Description
T天在道路的防守上花费最少的军粮。
样例输入 Sample Input
3 3 5 10 30
1 2 1
2 3 2
1 3 4
1
1 3 2 5
样例输出 Sample Output
180
数据范围及提示 Data Size & Hint
各个测试点1s
最小生成树+DP
先处理出第i天到第j天之间通用的最小生成树,记作sol[i][j]
然后dp,决策某连续的一段时间内用同一个方案: f[i]=min(f[i],f[j]+sol[j+1][i]*(每人耗粮数)*(天数i-j)+k)
1 /*by SilverN*/ 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 const int mxn=320; 10 int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 // 17 struct edge{ 18 int x,y,dis; 19 }e[6010]; 20 int cmp(edge a,edge b){return a.dis<b.dis;} 21 int mct=0; 22 //边 23 int mp[mxn][mxn][51]; 24 bool check(int x,int y,int st,int ed){ 25 for(int i=st;i<=ed;++i)if(mp[x][y][i])return 0; 26 return 1; 27 } 28 //ban 29 int n,m,t,cv,k,q; 30 int fa[mxn];//并查集fa 31 int bas[mxn];//并查集初始化 32 //基本 33 void init(){memcpy(fa,bas,sizeof fa);return;} 34 int find(int x){ 35 if(fa[x]==x)return x; 36 return fa[x]=find(fa[x]); 37 } 38 //并查集 39 int kruskal(int st,int ed){ 40 memcpy(fa,bas,sizeof fa); 41 int num=1; 42 int res=0; 43 int i,j; 44 for(i=1;i<=m;++i){ 45 if(!check(e[i].x,e[i].y,st,ed))continue; 46 int x=find(e[i].x); 47 int y=find(e[i].y); 48 if(x==y)continue; 49 fa[x]=y; 50 res+=e[i].dis; 51 ++num; 52 if(num==n)break; 53 } 54 if(num!=n)return 0x3f3f3f3f; 55 return res; 56 } 57 // 58 int f[60]; 59 int sol[60][60]; 60 int DP(){ 61 memset(f,0x3f,sizeof f); 62 f[0]=0; 63 int i,j; 64 for(i=1;i<=t;++i) 65 for(j=0;j<i;++j){ 66 if(sol[j+1][i]==0x3f3f3f3f)continue; 67 f[i]=min(f[i],f[j]+sol[j+1][i]*cv*(i-j)+k); 68 } 69 return f[t]; 70 } 71 // 72 int main(){ 73 int i,j; 74 n=read();m=read();t=read();cv=read();k=read(); 75 for(i=1;i<=n;++i){bas[i]=i;} 76 int x,y,d,st,ed; 77 for(i=1;i<=m;++i){//道路 78 e[i].x=read();e[i].y=read();e[i].dis=read(); 79 } 80 sort(e+1,e+m+1,cmp); 81 // 82 q=read(); 83 for(i=1;i<=q;++i){//破坏道路 84 x=read();y=read();st=read();ed=read();ed=min(ed,t); 85 for(int p=st;p<=ed;++p){ 86 mp[x][y][p]=mp[y][x][p]=1; 87 } 88 } 89 // printf("fin "); 90 memset(sol,0x3f,sizeof sol); 91 for(i=1;i<=t;++i){//每天情况 92 for(j=i;j<=t;++j){ 93 sol[i][j]=kruskal(i,j); 94 } 95 } 96 int ans=DP();//答案 97 printf("%d ",ans); 98 return 0; 99 }