TYVJ P1064 新三国争霸
题目:
http://www.tyvj.cn/Problem_Show.asp?id=1064
TYVJ格式问题,这里不贴题了。
题解:
一道非常不错的DP~~~~~~
f[i]=min(f[j]+(i-j)*v*get(j+1,i)+k)(0<=j<i),用f[i]表示到第i天的最小费用为多少,则转移方程表示在第j+1天到第i天方案不变的费用。get(a,b)表示从第a天到第b天方案保持不变最小需要多少人,这个问题可以先排除不可用边后求最小生成树得到所需的值。枚举i,j,每次再做一次做小生成树,最终复杂度可以变为O(n*n*m)(在一开始时排一次序即可不用每次对选出的边排序,当然是用克鲁斯卡尔,虽然我的程序没有使用这个优化)
题不难,但非常不错~~~~~~
View Code
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<algorithm>
5
6 using namespace std;
7
8 const int maxn=601;
9 const int maxm=10001;
10 const int maxt=100;
11
12 long long f[maxt];
13
14 int x[maxm],y[maxm],z[maxm],fa[maxn],p,n,m,v,k,dt1[maxm],dt2[maxm],ds[maxm],de[maxm],t;
15
16 bool able[maxn][maxn];
17
18 struct edge
19 {
20 int s,e,v;
21 bool operator<(const edge &a)const
22 {
23 return v<a.v;
24 }
25 }ed[maxm];
26
27 int getf(int now)
28 {
29 if (now==fa[now]) return now;
30 else return fa[now]=getf(fa[now]);
31 }
32
33 long long get(int t1,int t2)
34 {
35 memset(able,false,sizeof(able));
36 for (int a=1;a<=p;a++)
37 if (((dt1[a]<=t2) && (t1<=dt1[a])) || ((dt2[a]<=t2) && (t1<=dt2[a])) || ((t1>=dt1[a]) && (t1<=dt2[a])) || ((t2>=dt1[a]) && (t2<=dt2[a]))) able[ds[a]][de[a]]=able[de[a]][ds[a]]=true;
38 int ll=0;
39 for (int a=1;a<=m;a++)
40 if (!able[x[a]][y[a]])
41 {
42 ll++;
43 ed[ll].s=x[a];
44 ed[ll].e=y[a];
45 ed[ll].v=z[a];
46 }
47 sort(ed+1,ed+ll+1);
48 for (int a=1;a<=n;a++)
49 fa[a]=a;
50 int add=0;
51 long long nowans=0;
52 for (int a=1;a<=ll;a++)
53 {
54 int f1=getf(ed[a].s);
55 int f2=getf(ed[a].e);
56 if (f1!=f2)
57 {
58 add++;
59 fa[f1]=f2;
60 nowans+=ed[a].v;
61 }
62 }
63 if (add!=n-1) return f[t+1];
64 else return nowans;
65 }
66
67 int main()
68 {
69 scanf("%d%d%d%d%d",&n,&m,&t,&v,&k);
70 for (int a=1;a<=m;a++)
71 scanf("%d%d%d",&x[a],&y[a],&z[a]);
72 scanf("%d",&p);
73 for (int a=1;a<=p;a++)
74 scanf("%d%d%d%d",&ds[a],&de[a],&dt1[a],&dt2[a]);
75 for (int a=1;a<=t+1;a++)
76 f[a]=123456789123456ll;
77 f[0]=0;
78 for (int a=1;a<=t;a++)
79 for (int b=0;b<a;b++)
80 f[a]=min(f[a],k+((long long)(v*(a-b)))*get(b+1,a)+f[b]);
81 printf("%I64d\n",f[t]);
82
83 return 0;
84 }