poj 3411 Paid Roads(dfs+標記路徑->求最少花費)
Description
A network of m roads connects N cities (numbered from 1 to N
- in advance, in a city ci (which may or may not be the same as ai);
- after the travel, in the city bi
The payment is Pi in the first case and Ri in the second case.
Write a program to find a minimal-cost route from the city 1 to the city N.
Input
The first line of the input contains the values of N and m
Output
The first and only line of the file must contain the minimal possible cost of a trip from the city 1 to the city N. If the trip is not possible for any reason, the line must contain the word ‘impossible’.
Sample Input
4 5 1 2 1 10 10 2 3 1 30 50 3 4 3 80 80 2 1 2 10 10 1 3 2 10 50
Sample Output
110
借鑑:
這題難點在於“城市與城市之間可能存在多條路徑”:
1、 輸入資料時可能會出現多條 從城市a到城市b的路徑資訊,但是費用有所差別;
2、 對於 從城市a到城市b 的同一條路徑,允許重複走。
有人會問,重複走同一條路徑有什麼意義?單純增加費用而已,為什麼不能標記所有路徑,每條路只允許走一次,這樣費用不是更少麼?
我開始也是陷入了這種思維,但是這種想法其實“對一半,錯一半”。
先來看一組資料:
6 5
1 2 1 10 10
2 3 4 10 100
2 4 2 15 15
4 1 1 12 12
3 6 6 10 10
如果每條路只允許走一次,那麼方案只有1個:
1à2à3à6 共135元
但這組資料的正確答案是67元。為什麼?正確的方案如下:
1à2à4à1à2à3à6 共67元
顯然1à2重複走了一次,目的是為了先到達城市4,從而使得2à3這段路的費用從100縮減到10元。
看到這裡很多同學好像就恍然大悟,但是問題馬上又來了。如果同一條路允許重複走,那麼就不能標記了,但一旦不標記,失去了搜尋的限制條件,DFS就無法結束,不是陷入死迴圈了?
我剛才說這種思路“對一半,錯一半”,“對”是對在“重複走會增加費用”,“錯”是錯在“重複走的物件不是某一條路,而是某一個環路”。在同一個環路重複走才會真正增加費用。但是標記環路是很麻煩的,那麼能不能根據某一條路或某一個城市重複走過的次數來判斷當前所走的方案已經出現了環路? 答案是可以的。
上述的例子已經驗證過了,同一條路可以重複走,但是不能無限重複走,重複的次數是有限的。那麼應該重複多少次才合理?這與m值有關。題目的m值範圍為<=10,那麼當人一個城市被到達的次數若 >3次(不包括3),所走的方案必然出現了環路(網上的同學稱之為“閘數”)。
因此只需把bool vist[] 修改為 int vist[] 進行標記,本題就能解決了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
const int N = 16;
struct node
{
int b, c, p, r;
};
vector<node>q[N];
const int inf = 0x3f3f3f3f;
int vis[N];
int ans, n, m;
void dfs(int u,int sum)
{
vis[u]++;
if(u==n)
{
if(ans>sum)
ans=sum;
return ;
}
if(sum>ans)
return ;
for(int i=0;i<q[u].size();i++)
{
int v1=q[u][i].b, v2=q[u][i].c;
if(vis[v1]<=3)
{
int cost=q[u][i].r;
if(vis[v2])
cost=min(cost,q[u][i].p);
dfs(v1,sum+cost);
vis[v1]--;
}
}
return ;
}
int main()
{
while(scanf("%d %d", &n, &m)!=EOF)
{
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
q[i].clear();
for(int i=0;i<m;i++)
{
int x, y, z, l1, l2;
scanf("%d %d %d %d %d",&x, &y, &z, &l1, &l2);
node e;
e.b=y, e.c=z, e.p=l1, e.r=l2;
q[x].push_back(e);
}
ans=inf;
dfs(1,0);
if(ans<inf)
printf("%d\n",ans);
else
printf("impossible");
}
return 0;
}