继第一篇的后续,又来刷水题了,写的是SPFA算法,这个算法的复杂度比较玄学,感觉能不用就不用了,但是他的好处就是可以判断负圈。

3月26日:
1.POJ 1847 Tram
题意:在一个交通网络上有N个路口, 每个路口指向多个方向, 默认驶向第一个方向, 驶向其他方向时需要进行一次操作, 求从a到b最小的操作数
直接建图即可,默认的方向权值为0,其他方向权值为1。

#pragma GCC optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <math.h>
#include <string>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#define maxn 110
//#define true false
//#define false true
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
const double pi = acos(-1);
typedef long long ll;
const int mod = 1e9 + 7;
using namespace std;
int n,st,en;
int visited[maxn];
struct wazxy{
    int v,next,w;
}edge[maxn*maxn];
int head[maxn];
int dis[maxn];
int cnt=0;
void init(){
    memset(visited,false,sizeof(visited));
    memset(dis,MaxN,sizeof(dis));
    memset(head,-1,sizeof(head));
}
void add(int u,int v,int w){
    edge[cnt].w=w;
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void spfa(){
    queue<int> q;
    q.push(st);
    dis[st]=0;
    while(!q.empty()){
        int temp=q.front();
        q.pop();
        visited[temp]=false;
        for(int i=head[temp];~i;i=edge[i].next){
            int v=edge[i].v;
            int w=dis[temp]+edge[i].w;
            if(dis[v]>w){
                dis[v]=w;
                if(!visited[v]){
                    visited[v]=true;
                    q.push(v);
                }
            }
        }
    }
}
int main()
{
    cin>>n>>st>>en;
    init();
    for(int i=1;i<=n;i++){
        int m,x;
        scanf("%d",&m);
        bool flag=true;
        for(int f=1;f<=m;f++){
            scanf("%d",&x);
            if(flag) add(i,x,0),flag=false;
            else add(i,x,1);
           // cout<<i<<" "<<x<<endl;
        }
    }
    spfa();
 // for(int i=1;i<=n;i++) cout<<dis[i]<<endl;
    if(dis[en]!=MaxN) printf("%d\n",dis[en]);
    else  printf("-1\n");
    return 0;
}

2.POJ 2502 Subway
首先,原谅我这个题做了一晚上,找了一个多小时的bug,当ac此题时,原谅我仰天长啸3s,出错原因竟然是极大值附小了,我他妈!!!!!!淦

题意:个人要从家到学校,步行速度10km/h,图上有地铁40km/h,地铁有不同线路,每个线路上的地铁可以互通,相邻两站之间地铁以直线运行,不同地铁线路之间不能直接通过地铁乘坐到达,但不同地点间可以直接步行,按直线走。给出家、学校、各地铁站台的坐标(单位 m),问从家到学校最短需要花费多少时间(min),不要忘记换算单位。

思路:先把每条铁路建成图(速度为车速),再把每个站点之间连起来(相当于人走)。

#pragma GCC optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <math.h>
#include <string>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#define maxn 100010
//#define true false
//#define false true
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
const double pi = acos(-1);
typedef long long ll;
const int mod = 1e9 + 7;
using namespace std;
int sx,sy,ex,ey;
int n;
bool visited[maxn];
struct wazxy{
    int v,next;
    double w;
}edge[maxn];
struct point{
    int x,y;
}a[maxn];
int head[maxn];
long double dis[maxn];
int cnt=0;
int num=1;
void init(){
    memset(visited,false,sizeof(visited));
    for(int i=0;i<maxn;i++) dis[i]=1e18;
    memset(head,-1,sizeof(head));
}
void add(int u,int v,double w){
    edge[cnt].w=w;
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void spfa(){
    queue<int> q;
    q.push(0);
    dis[0]=0;
    while(!q.empty()){
        int temp=q.front();
        q.pop();
        visited[temp]=false;
        for(int i=head[temp];~i;i=edge[i].next){
            int v=edge[i].v;
            double w=dis[temp]+edge[i].w;
            if(dis[v]>w){
                dis[v]=w;
                if(!visited[v]){
                    visited[v]=true;
                    q.push(v);
                }
            }
        }
    }
}
inline double getlen(double x,double y,double x1,double y1,double s){
    return 60*sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1))/s/1000;
}
int main()
{
    cin>>sx>>sy>>ex>>ey;
    int x,y,x1,y1;
    a[0].x=sx,a[0].y=sy;
    init();
    while(scanf("%d%d",&x,&y)!=EOF){
        a[num].x=x,a[num++].y=y;
        while(scanf("%d%d",&x1,&y1)!=EOF&&x1!=-1){
            a[num].x=x1,a[num++].y=y1;
            double temp=getlen(x,y,x1,y1,40);
        // cout<<temp<<endl;
            add(num-2,num-1,temp);
            add(num-1,num-2,temp);
            x=x1,y=y1;
        }
    }
    a[num].x=ex,a[num++].y=ey;
    for(int i=0;i<num;i++){
        for(int j=0;j<num;j++){
            if(i==j) continue;
            double temp=getlen(a[i].x,a[i].y,a[j].x,a[j].y,10);
           // cout<<temp<<endl;
            add(i,j,temp);
        }
    }
    num--;
    spfa();
    //for(int i=0;i<=num;i++) cout<<dis[i]<<endl;
    printf("%d\n",(int)(dis[num]+0.5));
    return 0;

}

3.POJ 1062 昂贵的聘礼
这个题只需要额外的一个附加条件,就是在某段区间内进行查询最短,在spfa种设置一个范围即可。

#pragma GCC optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <math.h>
#include <string>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#define maxn 1010
//#define true false
//#define false true
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
const double pi = acos(-1);
typedef long long ll;
ll mod = 998244353;
using namespace std;
struct wazxy{
    int v,w,next;
}edge[100010];
bool visited[maxn];
int dis[maxn];
int lv[maxn];
int cnt=0;
int head[maxn];
int n,m;
void add(int u,int v,int w){
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
int spfa(int l,int r){
    memset(visited,false,sizeof(visited));
    memset(dis,MaxN,sizeof(dis));
    queue<int> q;
    dis[0]=0;
    q.push(0);
    while(!q.empty()){
        int temp=q.front();
        q.pop();
        visited[temp]=false;
        for(int i=head[temp];~i;i=edge[i].next){
            int v=edge[i].v;
            if(!(lv[v]>=l&&lv[v]<=r)) continue;
            int w=dis[temp]+edge[i].w;
            if(dis[v]>w){
                dis[v]=w;
                if(!visited[v]){
                    visited[v]=false;
                    q.push(v);
                }
            }
        }
    }
    return dis[1];
}
int main()
{
    memset(head,-1,sizeof(head));
    cin>>m>>n;
    for(int i=1;i<=n;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        add(0,i,x);
        lv[i]=y;
        while(z--){
            int v,w;
            scanf("%d%d",&v,&w);
            add(v,i,w);
        }
    }
    int imin=MaxN;
    for(int i=lv[1]-m;i<=lv[1];i++){
        imin=min(imin,spfa(i,i+m));
    }
    cout<<imin<<endl;
    return 0;
}

3月30
4.poj1860 Currency Exchange floyd
出去爬了个泰山,还是比较累的,继续鏖战最短路
思路:这个题目利用了spfa判断正环,这个做法是最保险的,因为如果存在正环的话金钱就会一直增加。
代码:

#pragma GCC optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <math.h>
#include <string>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#define maxn 1010
//#define true false
//#define false true
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
const double pi = acos(-1);
typedef long long ll;
ll mod = 998244353;
using namespace std;
int visited[maxn];
double dis[maxn];
int n,m,s;
double v;
int head[maxn];
struct wazxy{
    double w;
    int next;
    double rate;
    int v;
}edge[1010];
int cnt=0;
int ans[maxn];
void add(int u,int v,double r,double w){
    edge[cnt].rate=r;
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
bool spfa(){
    queue<int> q;
    q.push(s);
    visited[s]=true;
    dis[s]=v;
    ans[s]++;
    while(!q.empty()){
        int temp=q.front();
        q.pop();
        visited[temp]=false;
        for(int i=head[temp];~i;i=edge[i].next){
            int to=edge[i].v;
            double r=edge[i].rate;
            double w=edge[i].w;
            if(dis[to]<(dis[temp]-w)*r){
                dis[to]=(dis[temp]-w)*r;
                if(!visited[to]){
                    visited[to]=true;
                    ans[to]++;
                    q.push(to);
                }
                if(ans[to]>n) return true;
            }
        }
    }
    return false;
}
int main()
{
    cin>>n>>m>>s>>v;
    memset(visited,false,sizeof(visited));
    memset(head,-1,sizeof(head));
    for(int i=0;i<maxn;i++) dis[i]=0;
    for(int i=1;i<=m;i++){
        int x,y;
        double a,b;
        cin>>x>>y>>a>>b;
        add(x,y,a,b);
        cin>>a>>b;
        add(y,x,a,b);
    }
    if(spfa()) cout<<"YES"<<endl;
    else cout<<"NO"<<endl;
    return 0;
}

昨晚本来想写,遗憾的是女朋友被猫咬了,陪她去医院***没写成;;
算了就写这些吧