# 圖論
## 歐拉路徑&漢米爾頓路徑
度:連接點的邊數
入度:進入某點邊的個數
出度:走出某點邊的個數
偶頂點:過點的線段為偶數條
奇頂點:過點的線段為奇數條
歐拉圖:能一筆畫完成的圖(一筆畫問題是考慮邊不是點)
歐拉路徑:由起點走到終點 (起點和終點可以不用相同)
歐拉迴路:由起點走回起點、圖形每條邊恰經過一次(起點和終點相同)
奇點為0個滿足歐拉迴路
理由:有進有出所以入度=出度,度數為偶
奇點為0或2個滿足歐拉路徑,且終點和起點為奇點
理由:入度<出度代表出了不會再進入,為起點 ; 入度>出度代表進入就不會再出,為終點
漢米爾頓(哈密頓):考慮點(歐拉圖考慮邊)、為NPC問題
漢米爾頓路徑跟歐拉路徑很像,只是漢米爾頓是每個點恰好經過一次(歐拉路徑是邊)
旅行銷售員問題為漢米爾頓迴路延伸
**歐拉迴路&歐拉路徑實作:**
```cpp=
#include<iostream>
#include<cstring>
using namespace std;
int graph[105][105],v[105],d[105],ans[105];
int n,m,k=0;//n為輸入幾行 m為點的個數
void dfs(int s){
for(int i=1;i<=m;i++)
if(graph[s][i]){
graph[s][i]=0;
graph[i][s]=0;
dfs(i);
}
ans[++k]=s;
}
int main(){
int start=1;
int cnt=0;
cin>>n>>m;
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++){
int a,b;//a為起點 b為終點
cin>>a>>b;
graph[a][b]=1;
graph[b][a]=1;
d[a]++;
d[b]++;
}
for(int i=1;i<=m;i++){
if(d[i]%2){
if(cnt==0)start=i;
cnt++;
}
}
if(cnt==0)dfs(start);
if(cnt==2){
dfs(start);
ans[k]=start;//奇點個數為偶,起點=終點
}
if(cnt==0||cnt==2){
for(int i=1;i<=k;i++)
cout<<ans[i]<<' ';
}
}
```
## 最短路徑
Single Sorce Shortest Path(單源最短路徑):
Dijkstra:
看所有點到起點的最短路徑,邊的權重不能為負(如果為負就沒辦法確定當前的路徑必為最短路徑)
實作方法:不斷更新到點的最短路徑,走到的下個點為更新後路徑最短且未走過的點,如果點v被選中就會產生從起點到v的最短路徑
**Dijkstra實作**:
```cpp=
#include<iostream>
#include<cstring>
#define INF 100000 //infinite
using namespace std;
int graph[105][105];
int dis[105];//distance
int arr[105];//判斷是否走過
int n,m;
void dijkstra(){
int cnt=1;
while(cnt<n){
int min_k=INF;
int k=-1;
for(int i=2;i<=n;i++){
if(arr[i])continue;
if(dis[i]<min_k){
k=i;
min_k=dis[i];
}
}
arr[k]=1;
cnt++;
for(int i=1;i<=n;i++){
if(!(arr[i])&&(dis[k]+graph[k][i])<dis[i]){
dis[i]=dis[k]+graph[k][i];
}
}
}
}
int main(){
cin>>n>>m; //n為點的個數 m為路徑數
memset(arr,0,sizeof(arr));
for(int i=1;i<=n;i++)dis[i]=INF;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
graph[i][j]=INF;
}
}
for(int i=1;i<=m;i++){
int a,b;
cin>>a>>b;//a到b的距離
cin>>graph[a][b];
if(a==1)dis[b]=graph[a][b];//如果為1到某點的距離可直接更新最短路徑
}
dis[1]=0;
arr[1]=1;
dijkstra();
cout<<"所有點到1的最短路徑:"<<'\n';
for(int i=1;i<=n;i++)cout<<dis[i]<<' ';
}
```