图论-存储&最短路

来源:互联网 发布:ucloud云计算创始人 编辑:程序博客网 时间:2024/06/05 05:10

今天讲图论......

基础就开心地跳过

图的存储

邻接矩阵没什么,注意一下初始化就好了,主要是邻接表。

曾经pascal用的指针,现在用的是静态链表,感觉很six。

const int MAXN=10010,MAXM=10010; struct line{int y,next;//如果有权值还要再开一个变量}l[MAXM];int n,m,f[MAXN]={0},num=0;inline void init(){int a,b;scanf("%d%d",&n,&m);//n个顶点,m条边 for(int i=1;i<=m;++i){scanf("%d%d",&a,&b);l[++num].y=b;//加入新的一个节点l[num].next=f[a];f[a]=num; //这里num可直接用i,无向图要反过来再存储一次 }return;}
图的最短路

有很多种做法......

洛谷p1529回家

我用的Floyed(当然了,这题有很多算法)它的思想类似dp,但是时间复杂度很高,数据范围大就会gg。

Floyed的k在最外层,个人理解是一个个加入顶点,判断能否松弛。

#include<bits/stdc++.h>using namespace std;int s[60]={0},f[55][55],p;inline void init(){    memset(f,10,sizeof(f));//用邻接矩阵存储    char x,y,t[10];    int xx,yy,z;    scanf("%d",&p);gets(t);    for(int i=1;i<=p;i++)//读入很恶心,啊    {        scanf("%c %c %d",&x,&y,&z);        if(x>='A'&&x<='Z')s[x-'A'+1]=1,xx=x-'A'+1;        else xx=x-'a'+27;        if(y>='A'&&y<='Z')s[y-'A'+1]=1,yy=y-'A'+1;        else yy=y-'a'+27;        if(z<f[xx][yy])f[xx][yy]=f[yy][xx]=z;        gets(t);    }    s[26]=0;    for(int i=1;i<=52;i++)f[i][i]=0;    return;}inline void floyd(){for(int k=1;k<=52;k++)//k在最外层哦for(int i=1;i<=52;i++)for(int j=1;j<=52;j++)f[i][j]=min(f[i][j],f[i][k]+f[k][j]);return;}inline void print(){    int mi=100000,k;    for(int i=1;i<=51;i++)    if(s[i]==1&&f[i][26]<mi)    {    mi=f[i][26];    k=i;    }    printf("%c %d",'A'+k-1,mi);    return;}int main(){init();floyd();print();return 0;}

洛谷p1339热浪

来一个dijkstra吧~

不断把离源点最近的点加入已搜索的行列(?

然后用这个点更新其余点的最短距离,不断重复。

#include<bits/stdc++.h>using namespace std;int ans[2600][2600],n,m,b,e,sum[2600]={0};int flag[2600]={0};inline void init(){    scanf("%d%d%d%d",&n,&m,&b,&e);    memset(ans,10,sizeof(ans));    for(int i=1;i<=n;i++)ans[i][i]=0;    for(int i=1;i<=m;i++)//为了初始化方便用的邻接矩阵    {        int x,y,v;        scanf("%d%d%d",&x,&y,&v);        if(ans[x][y]>v)ans[x][y]=ans[y][x]=v;    }    return;}inline void di(){    for(int i=1;i<=n;i++)sum[i]=ans[b][i];//初始化    flag[b]=1;    for(int i=1;i<n;i++)    {        int mi=100000,k=0;        for(int j=1;j<=n;j++)//贪心一波        if(flag[j]==0&&sum[j]<mi)        {            mi=sum[j];            k=j;        }        if(k==0)return;        flag[k]=1;//加入已搜队伍        for(int j=1;j<=n;j++)//更新其余点最短距离        if(flag[j]==0)sum[j]=min(sum[j],sum[k]+ans[j][k]);        if(flag[e]==1)return;    }    return;}int main(){    init();    di();    printf("%d",sum[e]);    return 0;}

洛谷p1828香甜的黄油

就决定是你了,Bellman-ford!

这题刚开始害怕复杂度,但是裸的Bellman-ford居然过了,emmmm......

bellman-ford的思想是用不断每一条边更新最短距离直到不再更新,

如果更新n次后仍未更新完,则说明有负权环(一条路径最多经过n个点,含n-1条边)。

#include<bits/stdc++.h>using namespace std;struct line{int l,r,w;}l[1500];int s[900][900],a[900]={0},n,p,c,flag[900],sum[900],num=0;int ans=1000000;inline void init(){scanf("%d%d%d",&n,&p,&c);for(int i=1;i<=n;i++){int t;scanf("%d",&t);a[t]++;//计算每个牧场的奶牛数}for(int i=1;i<=p;i++)for(int j=1;j<=p;j++)s[i][j]=100000;for(int i=1;i<=p;i++)s[i][i]=0;for(int i=1;i<=c;i++){int x,y,v;scanf("%d%d%d",&x,&y,&v);if(s[x][y]>v)//为了不重复,弄了个实际没什么用的邻接矩阵{    s[x][y]=s[y][x]=v;    l[++num].l=x;    l[num].r=y;    l[num].w=v;    l[++num].r=x;    l[num].l=y;    l[num].w=v;}}return;}inline void bell(int b){for(int i=1;i<=p;i++)sum[i]=100000;sum[b]=0;for(int i=1;i<=p;i++){bool re=false;for(int j=1;j<=num;j++)if(sum[l[j].l]+l[j].w<sum[l[j].r]){sum[l[j].r]=sum[l[j].l]+l[j].w;re=true;}if(re==false)break;}int ss=0;for(int i=1;i<=p;i++)ss+=a[i]*sum[i];ans=min(ans,ss);return;}int main(){        init();for(int i=1;i<=p;i++)di(i);printf("%d",ans);return 0;}

洛谷p3371模版题

这题我用了SPFA,思路是运用队列优化Bellman-ford,

如果当前加入的边可以松弛,则将该边的末端点加入队列等待松弛。

#include<bits/stdc++.h>using namespace std; const int MAXN=10010,MAXM=500010; struct line{int y,next,w;}l[MAXM];int n,m,f[MAXN]={0},num=0,begin;int ans[MAXN],flag[MAXN]={0},q[MAXN*MAXN]={0};inline void init(){int a,b,v;scanf("%d%d%d",&n,&m,&begin);for(int i=1;i<=m;++i){scanf("%d%d%d",&a,&b,&v);l[++num].y=b;l[num].w=v;l[num].next=f[a];f[a]=num;}return;}inline void spfa(int b){ans[b]=0;flag[b]=1;int head=1,tail=1;q[head]=b;while(head<=tail){int t=q[head];for(int i=f[t];i;i=l[i].next)if(ans[t]+l[i].w<ans[l[i].y]){ans[l[i].y]=ans[t]+l[i].w;if(flag[l[i].y]==0){q[++tail]=l[i].y;flag[l[i].y]=1;}}head++;flag[t]=0;//出队后要改变该点为可入队!!! }return;}int main(){init();for(int i=1;i<=n;i++)ans[i]=2147483647;spfa(begin);for(int i=1;i<n;i++)printf("%d ",ans[i]);printf("%d",ans[n]);return 0;}
有时间写个比较吧(flag


原创粉丝点击