【DP+ShortPath】[Dota1000]德鲁伊(Dyrad)

时间限制:10000ms 内存限制:100000kB
描述
德鲁伊带着他的精灵熊在前线作战……
德鲁伊打到了钱,会让他的熊宝宝回家买东西
德鲁伊在1号点,家在M号点,中间有e条无向边,通过每一条边都有一个时间,德鲁伊会让他的熊宝宝买N次东西,熊宝宝会选一条路来回家,但是这些点有限制,每一个点在一定的次数内不能通过,所以,熊宝宝有时候会更换路径。
德鲁伊可以让他的熊宝宝瞬间到他身边,所以熊宝宝买完东西回来不需要时间。
熊宝宝的路径是德鲁伊想的,所以每次熊宝宝更换路径都要耗费K的时间(第一次想的路径不花时间)
现在,德鲁伊想知道,买N次东西最少所需要的总时间是多少?
输入
第一行,四个数N,M,K,e
接下来e行,每行三个数s,t,len,表示s到t有一条无向边,通过时间为len
下面一行有一个数T,表示有T条限制
接下来T行,每行三个数x,l,r,表示在l次到r次不能通过x
输出
一个数,表示最短总时间
样例输入
5 5 10 8
1 2 1
1 3 3
1 4 2
2 3 2
2 4 4
3 4 1
3 5 2
4 5 2
4
2 2 3
3 1 1 
3 3 3
4 4 5
样例输出
32
提示
N<=10000,M<=10,K<=5000
T<=100

【Solution Of Loogint】

本题是浙江省选的一道水题的变形,这道题是一道较简单的动态规划。

F[i]表示到第i次所需要的最少时间

F[i]←min{F[j]+SPFA(j+1,i)*(i-j)+k}(0<=j<=i-1)

最后结果是F[n]-k

方程中的SPFA表示的是从j+1天到i天不改变方案所能取得的最短路径长度,这个只要对SPFA中的vis数组进行一定的预处理即可。

但魂之挽歌那个魂淡把n从100加强到了10000,O(n^2)的程序就跑得很吃力了…

【Code 1: Tle】

  1: Program Dryad(input,output);
  2:   type point=^node;
  3:        node=record
  4:          data,weight:longint;
  5:          next:point;
  6:   end;
  7:   var que:array[1..2000]of longint;
  8:       vis,forbid:array[1..20]of boolean;
  9:       dist:array[1..20]of longint;
 10:       limit:array[1..100,0..100]of longint;
 11:       map:array[1..20]of point;
 12:       F:array[0..100]of longint;
 13:       i,j,n,m,k,e,x,y,len,t,w,l,r:longint;
 14:       p:point;
 15:   Function SPFA(l,r:longint):longint;
 16:     var i,j,head,tail,quehead:Longint;edge:point;
 17:     begin
 18:       fillchar(que,sizeof(que),0);
 19:       fillchar(vis,sizeof(vis),false);
 20:       for i:=1 to m do dist[i]:=19940805;
 21:       fillchar(forbid,sizeof(forbid),false);
 22:       for i:=l to r do
 23:         for j:=1 to limit[i,0] do
 24:           forbid[limit[i,j]]:=true;
 25:       dist[1]:=0;vis[1]:=true;
 26:       head:=0;tail:=1;
 27:       que[tail]:=1;
 28:       while head<tail do
 29:         begin
 30:           inc(head);
 31:           quehead:=que[head];
 32:           vis[quehead]:=false;
 33:           edge:=map[quehead];
 34:           while edge<>nil do
 35:             begin
 36:               if not forbid[edge^.data] then
 37:                 if dist[quehead]+edge^.weight<dist[edge^.data] then
 38:                   begin
 39:                     dist[edge^.data]:=dist[quehead]+edge^.weight;
 40:                     if not(vis[edge^.data]) then
 41:                       begin
 42:                         inc(tail);
 43:                         que[tail]:=edge^.data;
 44:                         vis[edge^.data]:=true;
 45:                       end;
 46:                   end;
 47:               edge:=edge^.next;
 48:             end;
 49:         end;
 50:       exit(dist[m]);
 51:     end;
 52:   begin
 53:     readln(n,m,k,e);
 54:     for i:=1 to e do
 55:       begin
 56:         readln(x,y,len);
 57:         new(p);p^.data:=y;p^.weight:=len;p^.next:=map[x];map[x]:=p;
 58:         new(p);p^.data:=x;p^.weight:=len;p^.next:=map[y];map[y]:=p;
 59:       end;
 60:     readln(t);
 61:     for i:=1 to t do
 62:       begin
 63:         readln(x,l,r);
 64:         for j:=l to r do
 65:           begin
 66:             inc(limit[j,0]);
 67:             limit[j,limit[j,0]]:=x;
 68:           end;
 69:       end;
 70:     for i:=1 to n do
 71:       begin
 72:         F[i]:=maxlongint;
 73:         for j:=0 to i-1 do
 74:           begin
 75:             w:=SPFA(j+1,i);
 76:             if w=19940805 then continue;
 77:             if F[i]>F[j]+w*(i-j)+k then
 78:               F[i]:=F[j]+w*(i-j)+k;
 79:           end;
 80:       end;
 81:     writeln(F[n]-k);
 82:   end.

{

This Code is Accepted at ZJOI2006_Trans.

http://www.zybbs.org/JudgeOnline/problem.php?id=1003

/**************************************************************

Problem: 1003

User: Loongint

Language: Pascal

Result: Accepted

Time:68 ms

Memory:304 kb

****************************************************************/

}

【Solution of Loongint】

注意到原题的数据范围:天数是100,而节点数是20。Dyrad这个题的数据:次数10000,节点只有10。

所以我们变换一下动归的方式。

先DFS处理出所有的路径,然后把每一条路径看成一个体积1,价值为其路径长度和的物品,那么就成为了一个背包问题,总体积为次数n。

F[i,j]表示到第i次且前一次所选择的路径为j所能获得的最短路程。

F[i,j]←min{F[i-1,j]+value[j],F[i-1,l]+value[l]+k}//j and l is legal in this time.

结果从F[n,i](1=<i<=MaxNumOfPath)中找即可。

效率是O(n*MaxNumPath)的。

代码不给了…因为Dsqwwe说,这样也超时,路径条数太多。

【Solution ③ of Loongint】

暴打魂之挽歌一顿…..(那家伙的代码ms是O(n)的….,马萨卡是贪心?)

原文地址:https://www.cnblogs.com/Loongint/p/2193553.html