1. 程式人生 > >bzoj 4289 TAX —— 點邊轉化

bzoj 4289 TAX —— 點邊轉化

www 之間 push_back tin lld font 集合 剛才 vector

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=4289

把邊轉化成點,同一個原有點相連的邊中,邊權小的向大的連差值的邊,大的向小的連0的邊;

一開始想的是給每個新點記一個點權是這個點(邊)原來的權,走到它時先加上點權,因為要在原圖上經過這條邊還是要花費邊權;

但是這樣在原圖中的邊之間轉移時會把它們的邊權都加上,就不對了;

所以應該是把原圖的邊進一步拆成兩個點,兩端點的集合各加入一個,這兩點之間連原邊權的邊;

題目上什麽也沒說...總之 dis 是 long long 的;

如果直接把剛才存邊用的結構體放進 queue,就要註意把結構體的 w 定義成 ll,而且一定註意結構體內部定義變量的順序!因為 (N){..., ...} 的寫法是強調順序的!

——然後發現這道題三個月前做過-_- https://www.cnblogs.com/Zinn/p/9326302.html

代碼如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define pb push_back
using namespace std;
typedef long long ll;
int const xn=2e5+5,xm=1e5+5;
int n,m,s,t,hd[xn<<1],ct,to[xn<<3],nxt[xn<<3],w[xn<<3]; ll dis[xn<<1]; bool vis[xn<<1]; struct N{ ll w; int id;//ll(dis) bool operator < (const N &y) const {return w<y.w;} }; vector<N>v[xm]; priority_queue<N>q; int rd() { int ret=0,f=1; char
ch=getchar(); while(ch<0||ch>9){if(ch==-)f=0; ch=getchar();} while(ch>=0&&ch<=9)ret=(ret<<3)+(ret<<1)+ch-0,ch=getchar(); return f?ret:-ret; } void add(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; w[ct]=z; hd[x]=ct;} void dij() { while(q.size()) { int x=q.top().id; q.pop(); if(vis[x])continue; vis[x]=1; for(int i=hd[x],u;i;i=nxt[i]) { if(dis[u=to[i]]>dis[x]+w[i]) dis[u]=dis[x]+w[i],q.push((N){-dis[u],u}); } } } int main() { n=rd(); m=rd(); s=0; t=2*m+1; for(int i=1,x,y,z;i<=m;i++) { x=rd(); y=rd(); z=rd(); v[x].pb((N){z,i}); v[y].pb((N){z,i+m}); add(i,i+m,z); add(i+m,i,z); } for(int i=0;i<v[1].size();i++)add(s,v[1][i].id,v[1][i].w); for(int i=0;i<v[n].size();i++)add(v[n][i].id,t,0);//0 for(int i=1;i<=n;i++) { sort(v[i].begin(),v[i].end()); for(int j=1;j<v[i].size();j++) add(v[i][j-1].id,v[i][j].id,v[i][j].w-v[i][j-1].w),add(v[i][j].id,v[i][j-1].id,0); } memset(dis,0x3f,sizeof dis); dis[s]=0; q.push((N){0,s}); dij(); printf("%lld\n",dis[t]); return 0; }

bzoj 4289 TAX —— 點邊轉化