●贅述題目
算了,題目沒有重復的必要。
注意理解:對答案造成貢獻的是每個點,就是了。
舉個栗子:
對於如下數據:
2 1
1 2 1
答案是 2;
●題解
方法:建圖(難點)+最短路。
先來幾個鏈接:(他們為我解題提供了思路,但有些部分看得我有點mengbi)
●http://blog.csdn.net/pure_w/article/details/55060079
●http://www.cnblogs.com/clrs97/p/5046933.html
●建圖:
1.把原圖的雙向邊拆成兩條單向邊(權值不變)。並把每條單向邊看成一個點(稱為新圖點);
2.建立源點S,S向1號點的出邊(新圖點)建單向邊,權值為那些出邊的權值。
3.建立匯點T,n號點的入邊(新圖點)向T建單向邊,權值為那些入邊的權值。
效果如下:
接下來是比較暴力的建邊
(4.)枚舉每個原圖點X,把它的每條入邊(新圖點)向每條出邊(新圖點)建邊,權值為這兩條出入邊的較大權值。(這樣導致邊巨多)
然后是比較優化的建邊
4.(似乎叫差分邊),枚舉每個原圖點X,先把它的出邊(新圖點)從小到大排序,排序后相鄰的出邊(新圖點)間建兩條有向邊,小的指向大的邊權為兩者權值之差,大的指向小的邊權為0。再枚舉它的每個入邊(新圖點),向該原圖點X的與該入邊(新圖點)權值相同的出邊建邊(為什么一定存在權值相同的入邊和出邊呢?因為我們把無向邊變成了兩個有向邊),權值就為該相同權值。
(4.)和4.的建圖效果如下:
最后,新圖已經建好,用4.建完圖后,點和邊的數量都可以接受,跑一個dijkstra就好啦!
●代碼
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
struct node{
int p;long long d;
bool operator <(const node &rtm) const {return d>rtm.d;}
};
struct edge{
int to,co,next;
}e[400005*2],E[2000000];
int headin[100005],headout[100005],head[400010],nextout[400005*2],nextin[400005*2];
int st[200005];
int n,m,dnt=2,ent=1,S,T,cnt,p;
ll dis[400010];
bool vis[400010];
bool cmp(int x,int y) {return e[x].co<e[y].co;}
void add(int u,int v,int c){
e[dnt]=(edge){v,c,0}; nextout[dnt]=headout[u];
e[dnt]=(edge){v,c,0}; nextin[dnt]=headin[v];
headout[u]=headin[v]=dnt++;
e[dnt]=(edge){u,c,0}; nextout[dnt]=headout[v];
e[dnt]=(edge){u,c,0}; nextin[dnt]=headin[u];
headout[v]=headin[u]=dnt++;
}
void ADD(int u,int v,int c) {E[ent]=(edge){v,c,head[u]}; head[u]=ent++;}
void make_something(int x){
cnt=0;
for(int i=headout[x];i;i=nextout[i]) st[++cnt]=i;
sort(st+1,st+cnt+1,cmp);
for(int i=1;i<cnt;i++) ADD(st[i],st[i+1],e[st[i+1]].co-e[st[i]].co),ADD(st[i+1],st[i],0);
for(int i=headin[x];i;i=nextin[i]) p=i^1,ADD(i,p,e[i].co);
}
void dijkstra(){
node u; int v;
memset(dis,0x7f,sizeof(dis));
priority_queue <node> q;
q.push((node){S,0}); dis[S]=0;
while(!q.empty()){
u=q.top(); q.pop();
if(vis[u.p]) continue; vis[u.p]=1;
for(int i=head[u.p];i;i=E[i].next){
v=E[i].to;
if(!vis[v]&&dis[v]>dis[u.p]+E[i].co){
dis[v]=dis[u.p]+E[i].co;
q.push((node){v,dis[v]});
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,a,b,c;i<=m;i++) scanf("%d%d%d",&a,&b,&c),add(a,b,c);
// 建源點和匯點
S=dnt++; T=dnt++;
for(int i=headout[1];i;i=nextout[i]) ADD(S,i,e[i].co);
for(int i=headin[n];i;i=nextin[i]) ADD(i,T,e[i].co);
//枚舉每一個原圖點
for(int i=1;i<=n;i++) make_something(i);
dijkstra(); printf("%lld",dis[T]);
return 0;
}


