tyvj 1064 新三国争霸 数据 一枚

本文探讨了在特定时间范围内的最小生成树问题,并利用Kruskal算法进行求解,通过时间作为循环变量,实现了最小代价的计算。文中详细介绍了F[I]表示法和try函数的作用,以及如何在时间约束下构建最小生成树。此外,还提供了优化策略和代码实现,最终通过一组数据验证了解决方案的有效性。

题目连接:http://www.tyvj.cn/Problem_Show.aspx?id=1064

首先,因为士兵是瞬间到达的,而且不会因为距离的远近而花费代价,所以,如果我们要进行更改,那么必定改最优值!

而最优值就是最小生成树的权值和,我们用时间作为一层层的循环,用F[I]表示i结束后,最小用的代价为多少。

而每次推则是默认一段时间内,不发生改变,于是,得到下面的公式:

F[I]:=MIN{F[J]+try(j+1,i)} (0<=j<i)

try(l,r)表示在时刻l~r中,用不是灾难的边构建一棵最小生成树的代价。

这其中可以加许多小优化,就不多说了。


建议用Kruska算法求最小生成树,因为经过处理后,最小生成树的总时间代价为O(T*T*M+MLOGM)!!

code:

var
  t1,t2,n,m,day,eat,change,i,j,x,y,z,dis:longint;
  f:array[0..60] of int64;
  a,b,c:array[0..10010] of longint;
  fa:array[0..310] of longint;
  g:array[0..310,0..310,0..60] of boolean;
  flag:boolean;
  l:array[0..20010] of boolean;
function get(x:longint):longint;
  begin
    if fa[x]<>x then fa[x]:=get(fa[x]);
    exit(fa[x]);
  end;

function work(k:longint):longint;
  var
    tot,ans,i,x,y:longint;
  begin
    for i:=1 to 2*m do
	  if g[a[i],b[i],k]=false then l[i]:=false;
    for i:=1 to n do
	  fa[i]:=i;
	ans:=0;
	tot:=0;
	for i:=1 to 2*m do
	  if l[i] then
	    begin
                  x:=0;
	      x:=get(a[i]);
                  y:=0;
		  y:=get(b[i]);
		  if x<>y then
		    begin
		      fa[x]:=y;
			  fa[a[i]]:=y;
			  ans:=ans+c[i];
			  tot:=tot+1;
		
		    end;
	    end;
	if tot=(n-1) then exit(ans) else exit(-1);
  end;
procedure sort(l,r: longint);
  var
    i,j,x,y: longint;
  begin
    i:=l;
    j:=r;
    x:=c[(l+r) div 2];
    repeat
      while c[i]<x do
        inc(i);
      while x<c[j] do
        dec(j);
      if not(i>j) then
        begin
          y:=a[i];
          a[i]:=a[j];
          a[j]:=y;

		  y:=b[i];
          b[i]:=b[j];
          b[j]:=y;

		  y:=c[i];
          c[i]:=c[j];
          c[j]:=y;
          inc(i);
          j:=j-1;
        end;
    until i>j;
    if l<j then
      sort(l,j);
    if i<r then
      sort(i,r);
  end;
begin
  read(n,m,day,eat,change);
  for i:=1 to m do
    begin
	  read(x,y,z);
	  a[i]:=x;
	  b[i]:=y;
	  c[i]:=z;
	  a[i+m]:=y;
	  b[i+m]:=x;
	  c[i+m]:=z;
	end;
  sort(1,m*2);
  read(dis);
  fillchar(g,sizeof(g),true);
  for i:=1 to dis do
    begin
	  read(x,y,t1,t2);
	  for j:=t1 to t2 do
	    g[x,y,j]:=false;
	  for j:=t1 to t2 do
	    g[y,x,j]:=false;	
    end;
  f[0]:=0;
  for i:=1 to day do
    begin
	  flag:=false;
	  f[i]:=maxlongint;
	  fillchar(l,sizeof(l),true);
	  for j:=i-1 downto 0 do
	    begin
		  if flag or (j<0) then break;
		  x:=work(j+1);
		  if x=-1 then flag:=true
		  else
		    begin
			  x:=x*eat*(i-j)+change;
			  if (x+f[j])<f[i] then f[i]:=x+f[j];
			end;
		end;
    end;
  writeln(f[day]);
end.


Orz Purpleslz 大神!!!!还有Oct_gap 201!

下面是一组数据

10 45 30 3 600
1 2 106
1 3 192
1 4 48
1 5 104
1 6 148
1 7 117
1 8 47
1 9 30
1 10 145
2 3 5
2 4 127
2 5 12
2 6 45
2 7 36
2 8 6
2 9 24
2 10 40
3 4 172
3 5 123
3 6 63
3 7 191
3 8 91
3 9 85
3 10 27
4 5 134
4 6 158
4 7 43
4 8 130
4 9 155
4 10 124
5 6 38
5 7 89
5 8 171
5 9 157
5 10 138
6 7 107
6 8 151
6 9 41
6 10 139
7 8 7
7 9 167
7 10 119
8 9 177
8 10 83
9 10 130
10
4 6 19 20
5 1 27 28
4 7 6 12
5 3 1 10
8 4 13 28
7 1 7 12
6 8 5 16
2 3 11 21
2 5 11 17
8 2 8 28


答案是24153

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值