图的存储方式
二维数组:
可以表示出有向图与无向图,权重,还有入度与出度(同一行)
链式存储:
可以表示出有向图与无向图,权重,还有入度与出度(主要:同一条链)
运用:
Dfs:深度优先
深度优先一般是求多少种情况,与递归密切相关。
也就是说深度优先是先算深度(与递归的深度一样)
请看1005文件或
http://zhjnc.acmclub.com/index.php?app=problem_title&id=702&problem_id=1104
#include
#include
char v[9],g[9][9];//v用来表示状态,是否被访问了
int n,ans;
void dfs(int k,int cur)
{
int i,j;
if(k==0) ans++; //深度
else for(i=cur-1;i>=k-1;i--) //宽度(广度)
{
for(j=0;j if(g[i][j]=='#'&&v[j]==0) { v[j]=1; //访问后 dfs(k-1,i); v[j]=0; //状态复原 } } } int main() { int k,i; while(scanf("%d%d",&n,&k)!=EOF,n!=-1||k!=-1) { memset(v,0,sizeof(v)); for(i=0;i scanf("%s",g[i]); ans=0; dfs(k,n); printf("%d\n",ans); } return 0; } Bfs: 广度优先 广度优先一般是求最短路径,与队列密切相关。 也就是说广度优先是先算宽度(与递归的宽度一样),也就是先把每一步的可走的情况全部入队。 http://zhjnc.acmclub.com/index.php?app=problem_title&id=702&problem_id=1101 #include #include #include using namespace std; struct num { int x,y,step; }star; bool v[8][8]; int f[][2]={{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2}}; int bfs(int ex,int ey) { int i; queue memset(v,false,sizeof(v)); v[star.x][star.y]=true; q.push(star); star.step=0; num head,tem; while(!q.empty()) { head=q.front(); q.pop(); for(i=0;i<8;i++)//宽度(广度) { tem.x=head.x; tem.y=head.y; tem.x+=f[i][0]; tem.y+=f[i][1]; tem.step=head.step+1; if(!v[tem.x][tem.y]&&tem.x>=0&&tem.x<8&&tem.y>=0&&tem.y<8) { if(tem.x==ex&&tem.y==ey) return tem.step; v[tem.x][tem.y]=true;//状态位不会复原 q.push(tem); //所有的宽度入队 } } } } int main(int argc, char* argv[]) { char s[2],e[2]; int ex,ey; while(~scanf("%s%s",s,e)) { star.x=s[0]-'a'; star.y=s[1]-'0'-1; ex=e[0]-'a'; ey=e[1]-'0'-1; if(!strcmp(s,e)) printf("To get from %s to %s takes 0 knight moves.\n",s,e); else printf("To get from %s to %s takes %d knight moves.\n",s,e,bfs(ex,ey)); } return 0; } 深度优先和广度优先的相同点和区别 相同点:他们一般都会有状态位来描述是否已经被访问了。它们都是开始点假设结束点都最后才知道,也就是结束的点是随机的,哪个点都有可能。(还有一种算法直接知道结束点和开始点)。它们都需要明确知道宽度和深度,而且是有一定规律的。 区别:深度优先的状态位可以恢复但广度优先的状态位不会恢复,因此这也说明了广度优先适合求最短路径,而不能求所有的情况。深度优先可以求出所有情况,因此也可以求出最长和最短路径,只不过深度优先求最短路径的时间会大大多于广度优先的时间。有权重的图且它们的大小不同一般不会用广度优先。 直接知道开始点和结束点(用深度优先会超时)(有向和无向图都可以)这道题很重要。 http://zhjnc.acmclub.com/index.php?app=problem_title&id=702&problem_id=1120 1 #include 2 #include 3 const int inf=1000000000; 4 int n,g[10][10]; 5 void floyd() 6 { 7 int i,j,k; 8 for(k=0;k 9 for(i=0;i 10 for(j=0;j 11 if(g[i][k]+g[k][j] 12 g[i][j]=g[i][k]+g[k][j]; 13 } 14 int main() 15 { 16 int m,a,b,l,i,j; 17 while(scanf("%d%d",&n,&m)!=EOF) 18 { 19 for(i=0;i 20 for(j=0;j 21 g[i][j]=inf; 22 while(m--) 23 { 24 scanf("%d%d%d",&a,&b,&l); 25 g[a-1][b-1]=g[b-1][a-1]=l; 26 } 27 floyd(); 28 scanf("%d%d",&a,&b); 29 if(g[a-1][b-1]==inf) 30 puts("No path"); 31 else 32 printf("%d\n",g[a-1][b-1]); 33 } 34 return 0; 35 } 图生成树(也可以求图最长和最短路径)参考tushu.txt 普里姆Prim:分a,b两组,a组是头节点,每个节点的最小边。也就是数组排序问题了(二维数组) int c[6][6]= { {0,0,0,0,0,0}, {0,0,6,9,5,13}, {0,6,0,6,7,8}, {0,9,6,0,9,3}, {0,5,6,9,0,3}, {0,13,8,3,3,0}}; void prim(int n) { int i,j,lowcost[10],cost[10],min,k; for(i=2;i<=n;i++) {lowcost[i]=c[1][i]; cost[i]=1; } cost[1]=0; for(i=2;i<=n;i++) { min=999999; k=i; for(j=2;j<=n;j++) { if(lowcost[j] { min=lowcost[j]; k=j; } } printf("<%d,%d> ",cost[k],k); cost[k]=0; for(j=2;j<=n;j++) { if(c[k][j] {lowcost[j]=c[k][j]; cost[j]=k;} } } } 克鲁斯卡尔:先把边排序,然后一个一个的链接。也就是数组中排序问题了(二维数组) struct edg { int t,l,w; }num[20]; int set[6]; int seeks(int v) { while(set[v]>0) v=set[v]; return v; } void krush(int e) { int j,i; for(i=1;i<=5;i++) set[i]=0; j=1,i=1; while(j<=5&&i { int v1=seeks(num[i].t); int v2=seeks(num[i].l); if(v1!=v2) { printf("(%d,%d) ",num[i].t,num[i].l); set[v1]=v2; j++; } i++; } } 与深度优先广度优先的区别 深度优先广度优先:适合于一张二维数组表,可以上下左右移动。二这两个算法更加适合于图和边的运用 相同:它们也需要有一个数组来记录状态。它们的开始点和结束点都是随机的。 图的拓扑结构:(邻接表) 也就是入度和出度,入度为零的点可以拆出来,然后它连接的点的入度减一。