描述
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。
思路:看到题,表示吓到了,一开始没有读懂,连样例都不知道怎么出来的。后来同组的dada以飞速ac,于是就向他求救了。大神就是大神,把边的信息存下来,用了个二维、三维的数组,然后就是dp部分了,穷举每一次不变安排的开始和终结点,注意j(起点)要从i-1到0,因为要对边的取得情况进行判断,用了flag数组和||运算。然后就是最小生成树求边权和的问题了,用的并查集的做法,很简单就能的出tt,最后f(i)=min(f(i),f(j)+tt*(i-j)*v+k)。
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct uses{
int st,en,va;
}tree[10000];
int road[500][500]={0},f[100],n,fa[500];
bool cn[500][500][100]={false},flag[500][500]={false};
int my_comp(const uses &x,const uses &y)
{
if (x.va<y.va) return 1;
return 0;
}
int root(int x)
{
if (fa[x]!=x) fa[x]=root(fa[x]);
return fa[x];
}
int main()
{
int sum,m,t,v,k,i,j,a,b,c,x,y,t1,t2,p,tot=0,ans,r2,r1;
cin>>n>>m>>t>>v>>k;
memset(f,127,sizeof(f));
for (i=1;i<=m;++i)
{
cin>>a>>b>>c;
if (a>n||b>n) continue;
road[a][b]=road[b][a]=c;
}
cin>>p;
for (i=1;i<=p;++i)
{
cin>>x>>y>>t1>>t2;
if (road[x][y]==0) continue;
if (t1>t2)
{
a=t1;t1=t2;t2=a;
}
if (t1>t) continue;
if (t2>t) t2=t;
for (j=t1;j<=t2;++j)
cn[x][y][j]=cn[y][x][j]=true;
}
f[0]=0;tot=0;
for (i=1;i<n;++i)
for (j=i+1;j<=n;++j)
if (road[i][j]>0)
{
++tot;
tree[tot].st=i;
tree[tot].en=j;
tree[tot].va=road[i][j];
}
sort(tree+1,tree+tot+1,my_comp);
for (i=1;i<=t;++i)
{
memset(flag,false,sizeof(flag));
for (j=i-1;j>=0;--j)
{
sum=1;
ans=0;
for (a=1;a<=n;++a)
fa[a]=a;
for (a=1;a<=tot;++a)
{
flag[tree[a].st][tree[a].en]=
flag[tree[a].st][tree[a].en]||(cn[tree[a].st][tree[a].en][j+1]);
if (!flag[tree[a].st][tree[a].en])
{
r1=root(tree[a].st);
r2=root(tree[a].en);
if (r1!=r2)
{
fa[r1]=r2;
ans=ans+tree[a].va;
++sum;
}
}
if (sum==n) break;
}
if (sum>=n)
f[i]=min(f[i],f[j]+ans*(i-j)*v+k);
}
}
cout<<f[t]<<endl;
}