Basic Graph Theorem by PolarisChiba
姓名:李昕威
PolarisChiba
清大準大一生
講台上這個人
答案的關鍵就在名字......
答案的關鍵或許就在長相......
int G[N][N];
for (int i = 1; i <= m; ++i) {
int a, b;
cin >> a >> b;
G[a][b] = 1;
// G[b][a] = 1;
}
for (int i = 1; i <= m; ++i) {
int a, b, w;
cin >> a >> b >> w;
G[a][b] = w;
// G[b][a] = w;
}vector<int> v[N];
for (int i = 0; i < m; ++i) {
int a, b;
cin >> a >> b;
v[a].push_back(b);
}
vector<pair<int,int>> v[N];
for (int i = 0; i < m; ++i) {
int a, b, w;
cin >> a >> b >> w;
v[a].push_back(make_pair(b, w));
v[b].push_back(make_pair(a, w));
}如果沒有地圖、沒有網路的話,你恐怕必須學會這一招
有甚麼方法可以在O(V)的時間內走過整張圖呢?
總之就先一直走,走到底
不能走的時候退回來,並標示走過了
繼續從其他能走的點走下去
退回來、走下去
退回原點,完成
bool visited[N];
vector<int> v[N];
void dfs(int x) {
visited[x] = 1;
for (auto i : v[x]) if (!visited[i]) {
// do something
dfs(i);
}
}相鄰兩點至少要有一點被佔領
bool visited[N];
int color[N];
vector<int> v[N];
void dfs(int x, int color) {
vistited[x] = 1;
col[x] = color;
bool ok = 1;
for (auto i:v[x]) {
if (!visited[i]) dfs(i, 1 - color);
}
}
//最後統計color為1 與為 0各有多少
//比較多的就是答案一層一層搜尋下去
一層一層搜尋下去
一層一層搜尋下去
一層一層搜尋下去
vector<int> v[N];
bool visited[N];
queue<int> q;
q.push(1);
visited[1] = 1;
while (q.size()) {
int u = q.front();
q.pop();
for (auto i:v[u]) if (!visited[i]) {
visited[i] = 1;
q.push(i);
}
}藍色是起點、黑色是目標、紅色是大火
一秒後,森林的情況
兩秒後,森林的情況
三秒後,森林的情況
四秒後,森林的情況,好像有點花QAQ
四秒後,森林的情況
維護的是「人在第T秒可以走到的地方」與
「火在第T秒會燒到的地方」
火先燒,人再走=>火先放進Queue再放人
那你可能需要上這堂課......
如何求 22 到其他點的最短路徑呢?
如何求 22 到其他點的最短路徑呢?
如何求 22 到其他點的最短路徑呢?
如何求 22 到其他點的最短路徑呢?
如何求 22 到其他點的最短路徑呢?
int dis[N];
queue<int> q;
q.push(1);
dis[1] = 0;
visited[1] = 1;
while (q.size()) {
int u = q.front();
q.pop();
for (auto i:v[u]) if (!visited[i]) {
visited[i] = 1;
dis[i] = dis[u] + 1;
q.push(i);
}
}int dis[N];
queue<int> q;
q.push(1);
dis[1] = 0;
visited[1] = 1;
while (q.size()) {
int u = q.top();
q.pop();
for (auto i:v[u]) if (!visited[i]) {
visited[i] = 1;
dis[i] = dis[u] + x;
q.push(i);
}
}這條路太遠的話,就嘗試其他路
不斷找最近的點,加進來,然後鬆弛其它點
不斷找最近的點,加進來,然後鬆弛其它點
不斷找最近的點,加進來,然後鬆弛其它點
不斷找最近的點,加進來,然後鬆弛其它點
不斷找最近的點,加進來,然後鬆弛其它點
所有已經加進來的點都不會再變小
#define mk make_pair
using pi = pair<int,int>;
priority_queue<pi, vector<pi>, greater<pi>> pq;
for (int i = 2; i <= n; ++i) d[i] = 1e9;
pq.push(mk(0, 1)); //
while( pq.size() ) {
pi u = pq.top();
pq.pop();
if (d[u.second] != u.first) continue;
for (auto i:v[u.second]) {
if (d[i.first] > u.first + i.second) {
d[i.first] = u.first + i.second;
pq.push(mk( d[i.first], i.first ));
}
}
}有負環的情況
有負環的情況
有負環的情況
有負環的情況
有負環的情況
有負環的情況
bool inque[N];
queue<int> q;
q.push(1);
inque[1] = 1;
while( q.size() ) {
int u = q.front();
q.pop();
inque[u] = 0;
for (auto i:v[u]) if ( d[i.first] > d[u] + i.second ) {
d[i.first] = d[u] + i.second;
if ( !inque[i.first] ) {
inque[i.first] = 1;
q.push(i.first);
}
}
}1. 題目會給
2. Bellmen-Ford
一個點最多被更新幾次?
一個點最多被更新幾次?
被同一個點重複更新的話,就有負環
因此最多被更新(V-1)次
int cnt[N];
bool SPFA() {
while( q.size() ) {
int u = q.front();
q.pop();
inque[u] = 0;
for (auto i:v[u]) if ( d[i.first] > d[u] + i.second ) {
if ( ++cnt[i.first] >= n ) return false;
d[i.first] = d[u] + i.second;
if ( !inque[i.first] ) {
inque[i.first] = 1;
q.push(i.first);
}
}
return true;
}
}
這條路太遠的話,就嘗試其他路
主動嘗試用C去鬆弛AB
主動嘗試用1, 2, 3, 4, 5去鬆弛所有路徑
按照順序,由一個點一個點嘗試去鬆弛所有路徑
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) {
if (G[i][j] == 0) dp[i][j] = 1e9;
else dp[i][j] = G[i][j];
}
for (int k = 1; k <= n; ++k)
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
dp[i][j] = min(
dp[i][j],
dp[i][k] + dp[k][j]
);自己到自己的距離為無限大
經過Floyd-Warshall後,自己可以由一個路徑走到自己
根沒有父節點
又或者根的父節點就是自己......
根的子節點的父節點是自己
沒有子節點的節點
每個節點的子節點最多只有兩個
有些節點的子節點超過兩個
紅橙黃綠藍靛紫黑白
紅橙黃綠藍靛紫黑白
void dfs(int x, int p) {
cout << x << endl;
dfs(l[x], x);
dfs(r[x], x);
}紅橙黃綠藍靛紫黑白
紅橙黃綠藍靛紫黑白
void dfs(int x, int p) {
dfs(l[x], x);
cout << x << endl;
dfs(r[x], x);
}紅橙黃綠藍靛紫黑白
紅橙黃綠藍靛紫黑白
void dfs(int x, int p) {
dfs(l[x], x);
dfs(r[x], x);
cout << x << endl;
}紅橙黃綠藍靛紫黑白
紅橙黃綠藍靛紫黑白
queue<int> q;
q.push(1);
while(q.size()) {
int u = q.front();
q.pop();
cout << u << endl;
q.push(l[u]);
q.push(r[u]);
}除了葉節點以外
cin >> input;
sort(input.begin(), input.end());
cout << input;from 德羅布狐狸-迷因大盜
一個最小生成樹的例子
將邊按照邊權由小到大排序
從小到大一條邊一條邊加進來
從小到大一條邊一條邊加進來
從小到大一條邊一條邊加進來
從小到大一條邊一條邊加進來
#define mk make_pair
#define F first
#define S second
vector<pair<int, pair<int,int>>>G;
for (int i = 1; i <= m; ++i) {
int a, b, w;
cin >> a >> b >> w;
G.pb(mk(w, mk(a, b)));
}
sort(G.begin(), G.end());
for (auto i:G) if (!same(i.S.F, i.S.S)) {
unite(i.S.F, i.S.S);
ans += i.F;
}先隨便選一個點
(一個點也算一棵樹)
將離目前的生成樹最近的點加進來
將離目前的生成樹最近的點加進來
將離目前的生成樹最近的點加進來
DONE
inline int prim() {
int ans = 0;
visited[1] = 1;
pq.push(make_pair(0, 1));
while (pq.size()) {
pi u = pq.top();
pq.pop();
if (visited[u.second]) continue;
visited[u.second] = 1;
ans += u.first;
for (auto i:v[u.second]) {
pq.push(i.second , i.first);
// second代 表 邊 權、 first代 表 連 到 的 點
}
}
return ans;
}
Kruskal
同個連通塊裡有很多條權重一樣的邊可以被加入
int pre = -1;
int ok = 0;
for (auto i:G) {
if ( same(i.S.F, i.S.S) ) {
if (i.F == pre) ok = 1;
if (ok) break;
continue;
}
unite(i.S.F, i.S.S);
pre = i.F;
}Directed Acyclic Graph(DAG)
有向無環圖
每次將出度為零的點push進序列
紅橙黃綠藍
每次將出度為零的點push進序列
紅橙黃綠藍
每次將出度為零的點push進序列
紅橙黃綠藍
每次將出度為零的點push進序列
紅橙黃綠藍
每次將出度為零的點push進序列
紅橙黃綠藍
DONE
int n, m, deg[1000009];
vector <int> s, ans, v[1000009], u[1000009];
//u是相反的邊
vector <int> TopologicalSort() {
for (int i = 1; i <= n; ++i) {
if (deg[i] == 0) s.push_back(i);
deg[i] = v[i].size();
}
while (s.size()) {
ans.push_back(s.back());
s.pop_back();
for (auto i:u[ans.back()]) {
deg[i]--;
if (!deg[i]) s.push_back(i);
}
}
return ans;
}vector <int> v[1000009];
bitset <1000009> visited;
int col[1000009];
inline bool dfs(int x, int color) {
bool isBip = 1;
col[x] = color;
visited[x] = 1;
for (auto i:v[x]) {
if (visited[i] && col[i] == col[x]) return false;
if (!visited[i]) isBip &= dfs(i, color^1);
}
return isBip;
}vector<int> v[N];
int cnt = 0;
// n 是點數
for (int i = 1; i <= n; ++i) {
cnt += (v[i].size() % 2);
}
if (cnt == 2) cout << "歐拉路徑";
else if (cnt == 0) cout << "歐拉迴路";
else cout << "NO";set<pair<int,int>> k;
vector<int> v[N];
void dfs(int x)
{
for(auto i:v[x]) if(k.find({i,x}) != k.end())
{
k.erase(k.find({i,x}));
k.erase(k.find({x,i}));
dfs(i);
}
ans.push_back(x);
}set<int> s[N];
set<pair<int,int>> k;
void dfs(int x) {
for(auto i:s[x]) if(k.find({i, x}) != k.end()) {
k.erase(k.find({i,x}));
k.erase(k.find({x,i}));
dfs(i);
}
ans.push_back(x);
}
vector<int> g[N];
int ve, leng;
void dfs(int x, int p, int s) {
for(auto i : g[x]) {
if(i.first == p) continue;
dfs(i.first, x, s + i.second);
}
if( leng < s ) {
ve = x;
leng = s;
}
}
dfs(1, -1, 0);
leng = -1;
dfs(ve, -1, 0);
cout << leng << '\n';
for(int i = 0; i < m; i++) {
cin >> a >> b;
g[a][b] = 1;
}
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
g[i][j] = min(g[i][j],g[i][k]+g[k][j]);
int ans = INF;
for(int i = 1; i <= n; i++) ans = min(ans,g[i][i]);
if(ans == INF) cout << 0 << '\n';
else cout << ans << '\n';void solve(string a, string b) {
int x = find(b.begin(), b.end(), a[0]) - b.begin();
int y = int(b.size())-x-1;
if(x > 0) solve(a.substr(1, x), b.substr(0, x));
if(y > 0) solve(a.substr(x + 1, y), b.substr(x + 1, y));
cout << a[0]; //根
}
signed main() {
string a, b;
while(cin >> a >> b) {
solve(a, b);
cout << '\n';
}
return 0;
}前提是你要會找環在哪
首先我們有一張長得像這樣的圖
要如何找到環開始的地方呢?
將一隻烏龜和一隻兔子放在起點
烏龜一次走一步
兔子一次走兩步
烏龜一次走一步
兔子一次走兩步
烏龜一次走一步
兔子一次走兩步
烏龜一次走一步
兔子一次走兩步
兔子和烏龜見面了
將兔子放回原點
烏龜依舊一次走一步
兔子改成一次走一步
然後就在起點相遇了
神不神奇、厲不厲害><
兔子和烏龜見面了
此時烏龜走的步數是環的倍數
此時烏龜走的步數是環的倍數加上柄的長度
胸前的騎士徽章、尊貴的英姿、優雅的舉止,以及正直的心。
在在證明你是佛德賽的騎士。可是…
可是我從來沒見過劍柄上的家徽。請問你到底是從何而來?
int dis[N];
queue<int> q;
q.push(1);
dis[1] = 0;
while (q.size()) {
int u = q.front();
q.pop();
for (auto i:v[u]) if (!visited[i]) {
visited[i] = 1;
dis[i] = dis[u] + 1;
q.push(i);
}
}int dis[N];
deque<int> d;
d.push_back(1);
dis[1] = 0;
while (q.size()) {
int u = d.front();
d.pop_front();
for (auto i:v[u]) {
if (visited[i]) continue;
visited[i] = 1;
if (i.second == 1) {
d.push_back(i.first);
dis[i.first] = dis[u] + 1;
} else {
d.push_front(i.first);
dis[i.first] = dis[u];
}
}
}