寫之前先給這個專題做個總結
知識點:單源最短路,全源最短路,求最短路中的最長邊,bellman ford算法求有負權的最短路,bellman or SPFA判斷環,反向建圖,差分約束,層次圖建立層點(連通點)。
應該是覆蓋最短路所有內容了
1.POJ 2387 Til the Cows Come Home
模板題
2.POJ 2253 Frogger
Floyd模板題,只要看到這個數據範圍衝就完事了(n<=800)
3.POJ 1797 Heavy Transportation
題意:求能到達終點的最大邊權最小
看題意很明顯這個題可以用二分答案做,然而我一直莫名其妙的wa?用最大生成樹的最小邊也wa,然後換了變形dij才過…
dij的堆要寫成大根堆,因爲要優先選擇邊權大,不然會wa
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#define maxn 200010
#define maxm 200010
using namespace std;
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int v,w;
}e[maxm];
int cnt,n,m,s,vis[maxn],dis[maxn];
vector<edge>p[100005];
struct node{
int w,now;
bool operator <(const node&x)const
{
return w<x.w;
}
};
priority_queue<node>q;
inline void dij(int s){
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s]=0x3f3f3f3f;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis[u])continue;
vis[u]=1;
for(int i=0;i<p[u].size();i++){
int v=p[u][i].v;
if(dis[v]<min(dis[u],p[u][i].w)){
dis[v]=min(dis[u],p[u][i].w);
q.push((node){dis[v],v});
}
}
}
}
signed main(){
int tt,qq=0;
cin>>tt;
while(tt--){
qq++;
n=read(),m=read();
memset(p,0,sizeof(p));
for(int i=1,x,y,z;i<=m;i++){
x=read(),y=read(),z=read();
p[x].push_back((edge){y,z});
p[y].push_back((edge){x,z});
}
dij(1);
printf("Scenario #%d:\n",qq);
printf("%d\n\n",dis[n]);
}
return 0;
}
4.POJ 3268 Silver Cow Party
題意:求所有牛來回party最短路的最大值
見到這種來回的,一般都是直接建反圖就完事了
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#define maxn 200010
#define maxm 200010
const int inf=0x3f3f3f3f;
using namespace std;
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int v,w;
}e[maxm];
int cnt,n,m,mm,s,vis[maxn],dis[maxn],dis1[maxn],vis1[maxn];
vector<edge>p[100005],p1[100005];
struct node{
int w,now;
bool operator <(const node&x)const
{
return w>x.w;
}
};
inline void dij(int s){
priority_queue<node>q;
for(int i=1;i<=n;i++){
dis[i]=inf;
}
memset(vis,0,sizeof(vis));
dis[s]=0;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis[u])continue;
vis[u]=1;
for(int i=0;i<p[u].size();i++){
int v=p[u][i].v;
if(dis[v]>dis[u]+p[u][i].w){
dis[v]=dis[u]+p[u][i].w;
q.push((node){dis[v],v});
}
}
}
}
inline void dij1(int s){
priority_queue<node>q;
for(int i=1;i<=n;i++){
dis1[i]=inf;
}
memset(vis1,0,sizeof(vis1));
dis1[s]=0;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis1[u])continue;
vis1[u]=1;
for(int i=0;i<p1[u].size();i++){
int v=p1[u][i].v;
if(dis1[v]>dis1[u]+p1[u][i].w){
dis1[v]=dis1[u]+p1[u][i].w;
q.push((node){dis1[v],v});
}
}
}
}
signed main(){
n=read(),m=read(),s=read();
mm=0;
for(int i=1,x,y,z;i<=m;i++){
x=read(),y=read(),z=read();
p[x].push_back((edge){y,z});
p1[y].push_back((edge){x,z});
}
for(int i=1;i<=n;i++){
if(i==s)continue;
dij(i);
dij1(i);
mm=max(mm,dis[s]+dis1[s]);
// cout<<i<<" "<<dis[s]<<" "<<dis1[s]<<endl;
}
cout<<mm;
return 0;
}
5.POJ 1860 Currency Exchange
讀題難度>解題難度
判環模板題
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#define maxn 200010
#define maxm 200010
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,cnt,ans,c=1;
double r1,r2,c1,c2;
int k;
double money;
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int u,v;
double r,c;
};
vector<edge>e;
double d[1005];
bool bellman(){
memset(d,0,sizeof(d));
d[k]=money;
for(int i=1;i<n;i++){
int ok=0;
for(int j=0;j<e.size();j++){
if((d[e[j].u]-e[j].c)*e[j].r>d[e[j].v]){
d[e[j].v]=(d[e[j].u]-e[j].c)*e[j].r;
ok=1;
}
}
if(!ok)break;
}
for(int i=0;i<e.size();i++){
if((d[e[i].u]-e[i].c)*e[i].r>d[e[i].v]){
return true;
}
}
return false;
}
signed main(){
cin>>n>>m>>k>>money;
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y>>r1>>c1>>r2>>c2;
e.push_back((edge){x,y,r1,c1});
e.push_back((edge){y,x,r2,c2});
}
if(bellman())cout<<"YES"<<endl;
else cout<<"NO"<<endl;
return 0;
}
6.POJ 3259 Wormholes
判環,比上一題還簡單,故略
7.POJ 1502 MPI Maelstrom
讀入難度>>解題難度
讀x的時候一定要注意這個坑…用string的話會出問題
讀入完直接跑Floyd就沒了
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#define maxn 200010
#define maxm 200010
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,w,cnt,ans,c=1;
int dis[105][105];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j)dis[i][j]=0;
else dis[i][j]=inf;
}
}
for(int i=2;i<=n;i++){
for(int j=1;j<=i-1;j++){
char x[50];
scanf("%s",x);
if(x[0]=='x'){
continue;
}
else{
int k=atoi(x);
dis[i][j]=k;
dis[j][i]=k;
}
}
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
int mm=0;
for(int i=2;i<=n;i++){
if(dis[1][i]!=inf){
mm=max(mm,dis[1][i]);
}
}
cout<<mm<<endl;
return 0;
}
8.POJ 3660 Cow Contest
給出一些列大小關係,問有多少頭牛的排名可以確定
思路其實很簡單,以大小關係建立單向邊,跑一遍Floyd,求出來dis[i][j]的值不爲inf就cnt[i] ,cnt[j]都+1,統計完之後如果值爲n-1就代表跟所有其他的牛都有確定大小關係,即爲答案
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,t,ans,mxn;
int dis[505][505],vis[505][505],cnt[505];
int main(){
cin>>n>>m;
memset(dis,inf,sizeof(dis));
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
dis[x][y]=1;
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j)continue;
if(dis[i][j]!=inf)cnt[j]++,cnt[i]++;
}
}
for(int i=1;i<=n;i++){
if(cnt[i]==n-1)ans++;
}
cout<<ans;
return 0;
}
9.POJ 2240 Arbitrage
套利,判環,這題之前在洛谷上面做過,用map亂搞,跑Floyd判斷是否有dis最終大於1,有就是有環,然而交vj直接給我TLE,換成bellman 判環 TLE,(poj懂的都懂好吧)沒有氧氣優化又沒有C++11真的吐了,傻逼測評姬
最終 SPFA判環可過
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
using namespace std;
int n,f;
double dis[50][50];
string a;
map<string,int>m;
double s;
string x,y;
struct edge{
int v;
double w;
};
vector<edge>e[5005];
double d[1005];
int cnt[10050];
int vis[10050];
bool spfa(){
int ct=0;
memset(cnt,0,sizeof(cnt));
queue<int>q;
for(int i=1;i<=n;i++){
d[i]=1;
vis[i]=1,
q.push(i);
}
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=0;i<e[u].size();i++){
int v=e[u][i].v;
double w=d[u]*e[u][i].w;
if(d[v]<w){
d[v]=w;
cnt[v]=cnt[u]+1;
if(ct>4*n)return true;
if(cnt[v]>=n)return true;
if(vis[v]==0)q.push(v),vis[v]=1;
}
}
}
return false;
}
int main(){
while(1){
int t;
f++;
cin>>t;
if(t==0)break;
m.clear();
memset(e,0,sizeof(e));
for(int i=1;i<=t;i++){
cin>>a;
m[a]=i;
}
cin>>n;
for(int i=1;i<=n;i++){
double z;
cin>>x>>z>>y;
e[m[x]].push_back((edge){m[y],z});
}
if(spfa())printf("Case %d: Yes\n",f);
else printf("Case %d: No\n",f);
}
return 0;
}
10.POJ 1511 Invitation Cards
UVA721
在vj上面一直wa,爲了驗證我的程序是對的,特意註冊賬號去UVA交了原題,AC了,poj爬
思路:建反圖
(本代碼在vj上過不了)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#define maxn 1000010
#define maxm 1000010
const int inf=0x3f3f3f3f;
using namespace std;
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int v,w;
}e[maxm];
int cnt,n,m,mm,s,vis[maxn],dis[maxn],dis1[maxn],vis1[maxn];
vector<edge>p[1000005],p1[1000005];
struct node{
int w,now;
bool operator <(const node&x)const
{
return w>x.w;
}
};
inline void dij(int s){
priority_queue<node>q;
for(int i=1;i<=n;i++){
dis[i]=inf;
}
memset(vis,0,sizeof(vis));
dis[s]=0;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis[u])continue;
vis[u]=1;
for(int i=0;i<p[u].size();i++){
int v=p[u][i].v;
if(dis[v]>dis[u]+p[u][i].w){
dis[v]=dis[u]+p[u][i].w;
q.push((node){dis[v],v});
}
}
}
}
inline void dij1(int s){
priority_queue<node>q;
for(int i=1;i<=n;i++){
dis1[i]=inf;
}
memset(vis1,0,sizeof(vis1));
dis1[s]=0;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis1[u])continue;
vis1[u]=1;
for(int i=0;i<p1[u].size();i++){
int v=p1[u][i].v;
if(dis1[v]>dis1[u]+p1[u][i].w){
dis1[v]=dis1[u]+p1[u][i].w;
q.push((node){dis1[v],v});
}
}
}
}
signed main(){
int tt;
cin>>tt;
while(tt--){
n=read(),m=read();
mm=0;
memset(p,0,sizeof(p));
memset(p1,0,sizeof(p1));
for(int i=1,x,y,z;i<=m;i++){
x=read(),y=read(),z=read();
p[x].push_back((edge){y,z});
p1[y].push_back((edge){x,z});
}
dij(1);
dij1(1);
for(int i=2;i<=n;i++){
mm+=dis[i]+dis1[i];
}
cout<<mm<<endl;
}
return 0;
}
11.POJ 3159 Candies
差分約束,太水了,甚至不能算模板,直接用dij建單邊就過了
模板在後面
12.POJ 2502 Subway
此題難點在於建圖,建圖難度>>解題難度
對每個相間車站建直線距離邊,再對所有點建歐幾里得距離邊,最後跑一遍dij
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
#define maxn 200010
#define maxm 200010
#define inf 0x3f3f3f3f
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int v;
double w;
}e[maxm];
int num;
int cnt,n,m,s,vis[maxn];
double dis[maxn];
vector<edge>p[100005];
struct node{
double w;
int now;
bool operator <(const node&x)const
{
return w>x.w;
}
};
priority_queue<node>q;
inline void dij(int s){
for(int i=1;i<=num;i++){
dis[i]=inf;
}
memset(vis,0,sizeof(vis));
dis[s]=0;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis[u])continue;
vis[u]=1;
for(int i=0;i<p[u].size();i++){
int v=p[u][i].v;
if(dis[v]>dis[u]+p[u][i].w){
dis[v]=dis[u]+p[u][i].w;
q.push((node){dis[v],v});
}
}
}
}
double juli(double x1,double y1,double x2,double y2,double tt){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))/tt/1000*60;
}
struct ta{
double x,y;
}stop[505];
int sx,sy,dx,dy;
int main(){
sx=read(),sy=read(),dx=read(),dy=read();
stop[1].x=sx;
stop[1].y=sy;
memset(dis,0x3f3f3f3f,sizeof(dis));
int x,y;
num=2;
while(~scanf("%d%d",&x,&y)){
stop[num].x=x,stop[num].y=y;
int xx,yy;
while(~scanf("%d%d",&xx,&yy)){
if(xx==-1&&yy==-1)break;
stop[num+1].x=xx;
stop[num+1].y=yy;
double d=juli(x,y,xx,yy,40);
p[num].push_back((edge){num+1,d});
p[num+1].push_back((edge){num,d});
x=xx;
y=yy;
num++;
}
num++;
}
stop[num].x=dx;
stop[num].y=dy;
for(int i=0;i<=num;i++){
for(int j=0;j<=num;j++){
if(i==j)continue;
double d=juli(stop[i].x,stop[i].y,stop[j].x,stop[j].y,10);
p[i].push_back((edge){j,d});
}
}
dij(1);
printf("%.f",dis[num]);
return 0;
}
13.POJ 1062 昂貴的聘禮
此題的題意真的是坑的讓人吐血…最開始理解成探險家最開始等級無限,接觸一個人之後就降等,降等之後不能跟高級商家交易,結果真正的題意是:探險家接觸過的所有人的等級差距都不能超過m
比如酋長的等級是5,m是2,你最開始跟等級7的人交易過,你就不能再跟<5的人交易了,所有其實是詢問長度爲m的一個區間(並且酋長的等級一定要包含在區間內),一共跑m+1次dij,建圖很簡單,每個物品從0向它建一條原價邊,再從它的前置物建優惠邊即可
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
#define maxn 200010
#define maxm 200010
#define inf 0x3f3f3f3f
#define int long long
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int v,w,dengji;
}e[maxm];
int cnt,n,m,s,vis[maxn],dis[maxn];
vector<edge>p[100005];
struct node{
int w,now;
bool operator <(const node&x)const
{
return w>x.w;
}
};
priority_queue<node>q;
inline void dij(int s,int dj1,int dj2){
for(int i=1;i<=n;i++){
dis[i]=inf;
}
memset(vis,0,sizeof(vis));
dis[0]=0;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis[u])continue;
vis[u]=1;
for(int i=0;i<p[u].size();i++){
int v=p[u][i].v;
if(dis[v]>dis[u]+p[u][i].w&&p[u][i].dengji>=dj1&&p[u][i].dengji<=dj2){
dis[v]=dis[u]+p[u][i].w;
q.push((node){dis[v],v});
}
}
}
}
signed main(){
m=read(),n=read();
int zui;
for(int i=1;i<=n;i++){
int money,dj,q;
money=read(),dj=read(),q=read();
if(i==1)zui=dj;
p[0].push_back((edge){i,money,dj});
for(int j=1;j<=q;j++){
int x,y;
x=read(),y=read();
p[x].push_back((edge){i,y,dj});
}
}
int qq=m;
int mm=0x3f3f3f3f;
for(int i=1;i<=m+1;i++){
dij(0,zui-qq,zui-qq+m);
// cout<<zui-qq<<" "<<zui-qq+m<<endl;;
qq--;
mm=min(dis[1],mm);
}
cout<<mm;
return 0;
}
14.POJ 1847 Tram
每個車站第一條邊權爲0,其他爲1,然後就是Floyd傻逼題了
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
#define maxn 200010
#define maxm 200010
#define inf 0x3f3f3f3f
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
int dis[105][105];
int a,b,n;
int m;
signed main(){
cin>>n>>a>>b;
memset(dis,inf,sizeof(dis));
for(int i=1;i<=n;i++){
int t;
cin>>t;
for(int j=1;j<=t;j++){
int x;
x=read();
if(j==1)dis[i][x]=0;
else dis[i][x]=1;
}
}
// for(int i=1;i<=n;i++){
// for(int j=1;j<=n;j++){
/// cout<<dis[i][j]<<" ";
// }
// cout<<endl;
// }
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
if(dis[a][b]!=inf)cout<<dis[a][b];
else cout<<"-1";
return 0;
}
15.LightOJ 1074 Extended Traffic
三次方會出負數…spfa判環
詢問的點不在環上且可到達輸出距離,否則直接疑惑
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
#define maxn 200010
#define maxm 200010
#define inf 0x3f3f3f3f
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
int d[5005];
int n,a[5005],q[5005];
int m,vis[5005],cs[5005];
struct edge{
int v,w;
};
vector<edge>e[5005];
void spfa(){
memset(d,inf,sizeof(d));
memset(vis,0,sizeof(vis));
memset(cs,0,sizeof(cs));
queue<int>q;
d[1]=0;
cs[1]=1;
q.push(1);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=0;i<e[u].size();i++){
int v=e[u][i].v;
int w=e[u][i].w;
if(d[v]>d[u]+w){
d[v]=d[u]+w;
if(vis[v]==0&&cs[v]<=n){
cs[v]++;
q.push(v);
vis[v]=1;
}
}
}
}
}
signed main(){
int tt,qq=0,p;
cin>>tt;
while(tt--){
cin>>n;
qq++;
for(int i=1;i<=n;i++){
a[i]=read();
}
cin>>m;
for(int i=1;i<=m;i++){
int u,v;
u=read(),v=read();
int dis=(a[v]-a[u])*(a[v]-a[u])*(a[v]-a[u]);
e[u].push_back((edge){v,dis});
}
cin>>p;
for(int i=1;i<=p;i++){
q[i]=read();
}
spfa();
printf("Case %d:\n",qq);
for(int i=1;i<=p;i++){
if(d[q[i]]<3||d[q[i]]>=inf||cs[q[i]]>n){
printf("?\n");
}
else{
printf("%d\n",d[q[i]]);
}
}
memset(e,0,sizeof(e));
}
return 0;
}
16.HDU 4725 The Shortest Path in Nya Graph
建圖題
每個點有它所屬的層,層之間有通道,對層之間所有點全部建邊肯定會炸,所以建立每一層的層點,即專門用來連接屬於這一層其他點的點
#include<bits/stdc++.h>
using namespace std;
#define maxn 200010
#define maxm 200010
#define inf 0x3f3f3f3f
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int v,w;
}e[maxm];
int cnt,n,m,c,vis[maxn],dis[maxn];
vector<edge>p[200005];
int cs[200005],layer[200005];
struct node{
int w,now;
bool operator <(const node&x)const
{
return w>x.w;
}
};
priority_queue<node>q;
inline void dij(int s){
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s]=0;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis[u])continue;
vis[u]=1;
for(int i=0;i<p[u].size();i++){
int v=p[u][i].v;
if(dis[v]>dis[u]+p[u][i].w){
dis[v]=dis[u]+p[u][i].w;
q.push((node){dis[v],v});
}
}
}
}
signed main(){
int tt;
cin>>tt;
for(int rr=1;rr<=tt;rr++){
n=read(),m=read(),c=read();
for(int i=1;i<=n;i++){
layer[i]=read();
cs[layer[i]]=1;
}
for(int i=1;i<=n;i++){
p[layer[i]+n].push_back((edge){i,0});
if(layer[i]-1>=1&&cs[layer[i]-1]==1){
p[i].push_back((edge){layer[i]-1+n,c});
}
if(layer[i]+1<=n&&cs[layer[i]+1]==1){
p[i].push_back((edge){layer[i]+1+n,c});
}
}
for(int i=1,x,y,z;i<=m;i++){
x=read(),y=read(),z=read();
p[x].push_back((edge){y,z});
p[y].push_back((edge){x,z});
}
// cout<<endl<<endl;
// for(int i=1;i<=n;i++){
// for(int j=0;j<p[i].size();j++){
// printf("%d %d %d\n",i,p[i][j].v,p[i][j].w);
// }
// }
dij(1);
if(dis[n]==inf)printf("Case #%d: -1\n",rr);
else printf("Case #%d: %d\n",rr,dis[n]);
memset(layer,0,sizeof(layer));
memset(cs,0,sizeof(cs));
memset(p,0,sizeof(p));
}
return 0;
}
17.HDU 3416 Marriage Match IV
網絡流,待補
18.HDU 4370 0 or 1
這題必須配放個圖
此題是我有史以來讀過題意最抽象的題目,沒有之一,讀了兩個小時沒讀懂
題目給了一些條件和一個矩陣,要你求一個矩陣使兩個矩陣對應點乘積和最小
思維轉化,給出的條件代表點1的出度爲1,點n的入度爲1,其他的所有點出入度相等,路徑長度非負,還有兩種特殊情況,圖中有從1 or n出發的環,這樣的情況下其他的點入度出度全爲0,也符合題目的條件
拿dij跑最短路,並判斷特殊情況
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m,a[305][305],d[305];
const int inf=0x3f3f3f3f;
int ans,h;
int vis[350];
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
void dij(int s){
memset(d,inf,sizeof(d));
memset(vis,false,sizeof(vis));
d[s]=0;
for(int i=1;i<=n;i++){
int t=-1;
for(int j=1;j<=n;j++){
if(vis[j]==false&&(t==-1||d[t]>d[j])){
t=j;
}
}
vis[t]=true;
for(int j=1;j<=n;j++){
d[j]=min(d[j],d[t]+a[t][j]);
if(j==s&&t!=s)h=min(h,d[t]+a[t][j]);
}
}
}
int main(){
while(cin>>n){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
a[i][j]=read();
}
}
h=inf;
dij(1);
ans=d[n];
int t=h;
h=inf;
dij(n);
t+=h;
cout<<min(ans,t)<<endl;
}
}
19.POJ 3169 Layout
差分約束模板來了
白書上經典例題
重點在於符號的判斷>=和<=是兩個方向,並且建立超級源點
建圖完跑bellman即可
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#define maxn 200010
#define maxm 200010
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,w,cnt,ans;
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int u,v,w;
};
vector<edge>e;
int d[1005];
bool bellman(){
memset(d,inf,sizeof(d));
d[1]=0;
for(int i=1;i<n;i++){
int ok=0;
for(int j=0;j<e.size();j++){
edge ee=e[j];
if(d[ee.v]>d[ee.u]+ee.w){
d[ee.v]=d[ee.u]+ee.w;
ok=1;
}
}
if(!ok)break;
}
for(int i=0;i<e.size();i++){
edge ee=e[i];
if(d[ee.v]>d[ee.u]+ee.w){
return true;
}
}
return false;
}
signed main(){
int ml,md;
n=read(),ml=read(),md=read();
for(int i=1;i<=ml;i++){
int u,v,w;
u=read(),v=read(),w=read();
e.push_back((edge){u,v,w});
}
for(int i=1;i<=md;i++){
int u,v,w;
u=read(),v=read(),w=read();
e.push_back((edge){v,u,-w});
}
for(int i=1;i<=n-1;i++){
e.push_back((edge){i+1,i,0});
}
if(bellman())cout<<"-1";
else{
if(d[n]>inf/2){
cout<<"-2";
}
else {
cout<<d[n];
}
}
return 0;
}
由於前天晚上和昨天身體超級難受就慢了一點點…而且最後幾個題把我攔住了…所以就花了三天
感覺寫一下題解還是挺有用的,真正的理解是能解釋給別人聽讓別人理解(費曼學習法),而且回顧整個專題也可以做一些反思,思考題與題之間的關聯和區別,溫故知新。
繼續保持學習狀態,衝!!!
要開始學高數和電路分析了(