2019-07-08 16:02:00
第三节暑期信息奥赛课——图论
绪言
图论这东西,纠缠我很久啦!我接触的第一道图论题是2017普及组D1T3 洛谷P3956 棋盘(dijkstra算法)
当时用暴力法,整了个不到50分,但是还是不会这个算法。
图论乃是NOIP的重点之一!
最短路径问题
----Floyd
时间复杂度O(n^3)
只有五行!!!死也要给我背下来!!!
#include<iostream> //#include<cstring> using namespace std; int main(){ int num,way; cin>>num>>way; int sz[num+1][num+1]; int tx,ty,tz; for(int n=1;n<=num;n++) for(int m=1;m<=num;m++) sz[n][m]=0xFFF; //memset(sz,0x3F,sizeof(sz); for(int n=1;n<=way;n++) { cin>>tx>>ty>>tz; sz[tx][ty]=min(sz[tx][ty],tz);//陷阱一:可能有重复输入两点距离 } for(int i=1;i<=num;i++) sz[i][i]=0;//自己到自己的距离是0 //核心代码 for(int k=1;k<=num;k++){//k一定是在最外层,在动规中是状态 for(int i=1;i<=num;i++) for(int j=1;j<=num;j++){ if(sz[i][j] > sz[i][k]+sz[k][j]);//寻找桥梁点k,会使得i to k&k to j比i to j更短 sz[i][j] = sz[i][k]+sz[k][j]; } } for(int i=0;i<num;i++){ for(int j=0;j<num;j++) cout<<sz[i][j]<<" "; cout<<endl; } return 0; }
----Dijkstra
基础版的O(n^2),代码稍长
可优化
#include<iostream> #include<cstring> using namespace std; const int MAXN=0x3F,inf=0x3F3F3F; int num,way,minNum,minIndex; int sz[MAXN][MAXN]; int dis[MAXN]; bool vis[MAXN]; void dij(int s){ memset(dis,1,sizeof(dis)); memset(vis,1,sizeof(vis)); for(int p=1;p<=num;p++) dis[p]=sz[s][p]; vis[s]=1; for(int j=1;j<=num;j++){ int minIndex=1,minNum=inf+1; for(int i=1;i<=num;i++) if(vis[i]==1 && dis[i]<minNum){ minNum=dis[i]; minIndex=i; } } vis[minIndex]=1; for(int i=1;i<=num;i++) if(vis[i]==1 && dis[i]>dis[minIndex]+sz[minNum][i]){ dis[i]==dis[minIndex]+sz[minNum][i]; } } int main(){ cin>>num>>way; int tx,ty,tz; //初始化 for(int n=1;n<=num;n++) for(int m=1;m<=num;m++) sz[n][m]=MAXN; //msmset(sz,0x3F,sizeof(sz); for(int n=1;n<=way;n++) { cin>>tx>>ty>>tz; sz[tx][ty]=min(sz[tx][ty],tz);//陷阱一:可能有重复输入两点距离 } dij(1); for(int i=1;i<=num;i++){ for(int j=1;j<=num;j++) cout<<sz[i][j]<<" "; cout<<endl; } return 0; } /* 1、把sz[1][j]搬到一个一维数组dis中(起点到其他所有点的距离) 2、松弛操作:从dis中找一个没用过,且最小的点 3、 */
最小生成树问题
----kruskal
要用到并查集哟(^U^)ノ~YO
#include<iostream> using namespace std; int n,m; const int MAXN=0x3F3F3F; int f[MAXN]; //并查集开始 int init(){//初始化 for(int i=1;i<=n;i++) f[i]=i; } int getf(int i){ if(i==f[i]) return i;//没有祖先,或者说就是它自己 else return f[i]=getf(f[i]);//有祖先,就把f[i]也变成即将查找到的它的祖先的祖先,状态压缩 } void merge(int a,int b ){ int x=getf(a); int y=getf(b); if(x!=y) f[x]=f[y]; } int main(){ int a,b,c; cin>>n>>m; init(); //初始化 for(int i=1;i<=m;i++) cin>>a>>f[a]; return 0; } /* kruskal算法 1、清除所有边 2、找两点使得距离最短,连线 3、用并查集判断有没有环(回路) 4、 */ /* 并查集 对一个集合进行合并,查找 1、把一个一维数组sz的值初始化为其下标 2、若A与B有关系,则sz[A]=B; 3、若A与C有关系 最后,有多少个下标仍是值的数值,就有 */
代码的输入有问题,记得修复!
----Prim
(未完待续......)
以后做到了再说吧。。。