一道實驗題的想法(圖)
這門課又雙叒叕要寫實驗了…
好在是最後一個實驗,做完了豈不就可以…(浮想聯翩ing)
言歸正傳,先來看看題目:
實驗七 圖的操作
一、 要求完成時間
實驗開始後的第八週之前完成
二、 實驗目的
掌握無向圖的創建、遍歷方法。
三、 實驗內容
1、創建圖類,存儲結構使用鄰接矩陣。
2、輸入圖的節點數 n(不超過 10 個)、邊數 m,節點分別用 1-n 代表。
3、採用“起始節點,終止節點,權值”輸入圖的 m 條邊,創建圖。
4、輸出從節點 1 開始的 BFS 遍歷,在遍歷過程中,如有多個可以選擇
的節點,則優先選擇編號較小的節點。
5、輸出從節點 1 開始的 DFS 遍歷,在遍歷過程中,如有多個可以選擇
的節點,則優先選擇編號較小的節點。
6、輸出從第 1 節點到第 n 節點最短路徑的長度,如果沒有路經,輸出 0。
四、 測試用例及答案
測試如下所有用例及答案,且確保運行後出現完全一樣的輸出,
(操作系統提示“請按任意鍵繼續….”等,可以不一樣。)
看起來貌似很容易是吧,本大少打了半天,看了看樣例,結果他長着樣:
這輸入的是個啥…
好吧,做完了實驗,開始想了想圖的一些東西,嗯,有那味兒了。
關於圖的知識,應該會在另一篇博文中寫道(寫不寫其實還是看本大少心情2333333333)
單純來講講實驗吧
創建圖類,那我們就得了解圖的組成,題目要求說無向加權圖,那麼我們的三個要素:頂點,邊,權值,那我們先來定義一個邊得類:
class edge{
public:
edge(string str);//構造函數
int begin;
int end;
int length;
};
edge::edge(string str) {
int n1,n2,theLength;
int strLength = str.length();
char strChar[strLength];
for(int i=0;i<strLength;i++)
strChar[i] = str.at(i);
n1 = strChar[0]-'0';
n2 = strChar[2]-'0';
int b = strLength-4;
if(b==1){
theLength = strChar[4]-'0';
} else if(b==2){
theLength = (strChar[4]-'0')*10 + (strChar[5]-'0');
} else if(b==3){
theLength = (strChar[4]-'0')*100+(strChar[5]-'0')*10+(strChar[6]-'0');
}
begin = n1;
end = n2;
length = theLength;
}
那個構造函數是爲了解析題目的輸入,不要在意這種細節23333333
既然邊有了,那麼該來構造圖了:
class WGraph
{
public:
int n;//頂點個數
int e;//邊數
int **a;
int noEdge = 0;
WGraph(int numberOfVer);//構造函數
};
初始化一個圖只需要知道它的點集,而且我們是使用鄰接矩陣來表示圖,那麼我們要對圖進行操作:插入帶權值的邊,進行寬度優先搜索,深度優先搜索,求最短路徑,接下來就好辦了,寫幾個方法並擴充剛剛定義的WGraph類:
class WGraph
{
public:
int n;//頂點個數
int e;//邊數
int **a;
int noEdge = 0;
public:
WGraph(int numberOfVer);
void insertEdge(edge *theEdge);
void bfs();//寬度優先搜索
void dfs();//深度優先搜索
void rdfs(int v,int reach[]);//深度優先搜索遞歸函數
void path();//最短路徑
};
WGraph::WGraph(int numberOfVer) {
n=numberOfVer;
a = new int *[n+1];
for(int i=0;i<n+1;i++){
a[i] = new int[n+1];
}
for(int i=1;i<n+1;i++)
for(int j=1;j<n+1;j++)
a[i][j] = noEdge;
}
void WGraph::insertEdge(edge *theEdge) {
int v1 = theEdge->begin;
int v2 = theEdge->end;
int length = theEdge->length;
if(a[v1][v2]==noEdge){
a[v1][v2] = length;
a[v2][v1] = length;
}
}
void WGraph::bfs() {
arrayQueue q;
arrayQueue out;
int v = 1;
int label = 1;
int reach[n+1];
for(int i=0;i<n+1;i++)
reach[i] = 0;
reach[v] = label;
q.push(v);
while (!q.empty()){
int w = q.front();
q.pop();
out.push(w);
for(int u=1;u<=n;u++){
if(a[w][u]!=0&&reach[u]==0){
q.push(u);
reach[u] = label;
}
}
}
int temp = out.size();
for(int i=0;i<temp;i++){
if(i==temp-1){
cout<<out.front()<<endl;
} else{
cout<<out.front()<<",";
}
out.pop();
}
}
void WGraph::dfs() {
int reach[n+1];
for(int i=0;i<=n;i++){
reach[i] = 0;
}
rdfs(1,reach);
int temp = m->size();
for(int i=0;i<temp;i++){
if(i==temp-1){
cout<<m->front()<<endl;
} else{
cout<<m->front()<<",";
}
m->pop();
}
}
void WGraph::rdfs(int v, int *reach) {
reach[v] = 1;
m->push(v);
for(int u = 1;u<=n;u++){
if(a[v][u]!=0&&reach[u]==0){
rdfs(u,reach);
}
}
}
void WGraph::path() {
int max = 1000;
int min,x;
int len[n+1];
len[1] = 0;
int reach[n+1];
for(int i=0;i<=n;i++){
reach[i] = 0;
}
reach[1]=1;
for(int i=2;i<=n;i++) {
len[i] = max;
}
for(int i=1;i<=n;i++){
if(a[1][i]!=0){
len[i] = a[1][i];
}
}
for(int i=1;i<n;i++){
min = max;
for(int j=1;j<=n;j++){
if(reach[j]==0&&len[j]<min){
min = len[j];
x = j;
}
}
reach[x] = 1;
for(int y=1;y<=n;y++){
if(a[x][y]!=0){
if(len[y]>len[x]+a[x][y]){
len[y] = len[x]+a[x][y];
}
}
}
}
if(len[n]==max){
cout<<0<<endl;
} else{
cout<<len[n]<<endl;
}
}
這便是關於圖的全部代碼,有些地方爲了契合題目輸出的需要,可能會有一些多餘(咬我啊)
接下來放上實驗的全部代碼:
#include <iostream>
#include <string>
using namespace std;
//邊
class edge{
public:
edge(string str);
public:
int begin;
int end;
int length;
};
edge::edge(string str) {
int n1,n2,theLength;
int strLength = str.length();
char strChar[strLength];
for(int i=0;i<strLength;i++)
strChar[i] = str.at(i);
n1 = strChar[0]-'0';
n2 = strChar[2]-'0';
int b = strLength-4;
if(b==1){
theLength = strChar[4]-'0';
} else if(b==2){
theLength = (strChar[4]-'0')*10 + (strChar[5]-'0');
} else if(b==3){
theLength = (strChar[4]-'0')*100+(strChar[5]-'0')*10+(strChar[6]-'0');
}
begin = n1;
end = n2;
length = theLength;
}
//隊列
class arrayQueue
{
public:
arrayQueue(int initialCapacity = 50);
~arrayQueue() {delete [] queue;}
bool empty() const {return theFront == theBack;}
int size() const
{return (theBack - theFront + arrayLength) % arrayLength;}
int& front()
{
return queue[(theFront + 1) % arrayLength];
}
int& back()
{
return queue[theBack];
}
void pop()
{
theFront = (theFront + 1) % arrayLength;
}
void push(const int& theElement);
private:
int theFront;
int theBack;
int arrayLength;
int *queue;
};
arrayQueue::arrayQueue(int initialCapacity)
{
arrayLength = initialCapacity;
queue = new int[arrayLength];
theFront = 0;
theBack = 0;
}
void arrayQueue::push(const int& theElement)
{
if ((theBack + 1) % arrayLength == theFront)
{
int* newQueue = new int[2 * arrayLength];
int start = (theFront + 1) % arrayLength;
if (start < 2)
copy(queue + start, queue + start + arrayLength - 1, newQueue);
else
{
copy(queue + start, queue + arrayLength, newQueue);
copy(queue, queue + theBack + 1, newQueue + arrayLength - start);
}
theFront = 2 * arrayLength - 1;
theBack = arrayLength - 2;
arrayLength *= 2;
queue = newQueue;
}
theBack = (theBack + 1) % arrayLength;
queue[theBack] = theElement;
}
arrayQueue *m = new arrayQueue;
//加權無向圖
class WGraph
{
public:
int n;//頂點個數
int e;//邊數
int **a;
int noEdge = 0;
public:
WGraph(int numberOfVer);
void insertEdge(edge *theEdge);
void bfs();
void dfs();
void rdfs(int v,int reach[]);
void path();
};
WGraph::WGraph(int numberOfVer) {
n=numberOfVer;
a = new int *[n+1];
for(int i=0;i<n+1;i++){
a[i] = new int[n+1];
}
for(int i=1;i<n+1;i++)
for(int j=1;j<n+1;j++)
a[i][j] = noEdge;
}
void WGraph::insertEdge(edge *theEdge) {
int v1 = theEdge->begin;
int v2 = theEdge->end;
int length = theEdge->length;
if(a[v1][v2]==noEdge){
a[v1][v2] = length;
a[v2][v1] = length;
}
}
void WGraph::bfs() {
arrayQueue q;
arrayQueue out;
int v = 1;
int label = 1;
int reach[n+1];
for(int i=0;i<n+1;i++)
reach[i] = 0;
reach[v] = label;
q.push(v);
while (!q.empty()){
int w = q.front();
q.pop();
out.push(w);
for(int u=1;u<=n;u++){
if(a[w][u]!=0&&reach[u]==0){
q.push(u);
reach[u] = label;
}
}
}
int temp = out.size();
for(int i=0;i<temp;i++){
if(i==temp-1){
cout<<out.front()<<endl;
} else{
cout<<out.front()<<",";
}
out.pop();
}
}
void WGraph::dfs() {
int reach[n+1];
for(int i=0;i<=n;i++){
reach[i] = 0;
}
rdfs(1,reach);
int temp = m->size();
for(int i=0;i<temp;i++){
if(i==temp-1){
cout<<m->front()<<endl;
} else{
cout<<m->front()<<",";
}
m->pop();
}
}
void WGraph::rdfs(int v, int *reach) {
reach[v] = 1;
m->push(v);
for(int u = 1;u<=n;u++){
if(a[v][u]!=0&&reach[u]==0){
rdfs(u,reach);
}
}
}
void WGraph::path() {
int max = 1000;
int min,x;
int len[n+1];
len[1] = 0;
int reach[n+1];
for(int i=0;i<=n;i++){
reach[i] = 0;
}
reach[1]=1;
for(int i=2;i<=n;i++) {
len[i] = max;
}
for(int i=1;i<=n;i++){
if(a[1][i]!=0){
len[i] = a[1][i];
}
}
for(int i=1;i<n;i++){
min = max;
for(int j=1;j<=n;j++){
if(reach[j]==0&&len[j]<min){
min = len[j];
x = j;
}
}
reach[x] = 1;
for(int y=1;y<=n;y++){
if(a[x][y]!=0){
if(len[y]>len[x]+a[x][y]){
len[y] = len[x]+a[x][y];
}
}
}
}
if(len[n]==max){
cout<<0<<endl;
} else{
cout<<len[n]<<endl;
}
}
int main()
{
cout<<"Input"<<endl;
string str1;
cin>>str1;
int str1Length = str1.length();
int n,m;
n = str1.at(0)-'0';
if(str1Length==3){
m = str1.at(2)-'0';
} else if(str1Length==4){
m = (str1.at(2)-'0')*10+(str1.at(3)-'0');
}
WGraph wg(n);
for(int i=0;i<m;i++){
string str2;
cin>>str2;
edge *e = new edge(str2);
wg.insertEdge(e);
}
cout<<"Output"<<endl;
wg.bfs();
wg.dfs();
wg.path();
cout<<"End";
return 0;
}
造福SDUers,有要的就拿走吧。
不管是東南風,還是西北風,都是我的歌,我的歌…