Professional Documents
Culture Documents
Httpscourses - Uet.vnu - Edu.vnpluginfile - Php378789assignsubmission Filesubmission Files64723422028189 Lê20Thành20Đạt PDF
Httpscourses - Uet.vnu - Edu.vnpluginfile - Php378789assignsubmission Filesubmission Files64723422028189 Lê20Thành20Đạt PDF
Httpscourses - Uet.vnu - Edu.vnpluginfile - Php378789assignsubmission Filesubmission Files64723422028189 Lê20Thành20Đạt PDF
A. Đồ thị vô hướng
/*int n,m;
set<int> adj[1001];
int degree[1001];
void inp(){
cin >> n >> m;
for(int i =0;i<m;i++){
int x,y;
cin>>x>>y;
adj[x].insert(y);
adj[y].insert(x);
degree[x]++;
degree[y]++;
}
}
void euler(int v){
stack<int> st;
vector<int> EC;
2
st.push(v);
while(!st.empty()){
int x = st.top();
if(adj[x].size()!=0){
int y = *adj[x].begin();
st.push(y);
adj[x].erase(y);
adj[y].erase(x);
}else {
st.pop();
EC.push_back(x);
}
}
reverse(begin(EC),end(EC));
for(int x:EC){
cout << x << " ";
}
}
int main(){
inp();
euler(1);
}
*/
int n, m;
vector<int> adj[1001];
vector<bool> visited(1001, false);
vector<int> degree(1001, 0);
void inp(){
cin >> n >> m;
for(int i=0;i<m;i++){
int x,y;
cin >> x >> y;
adj[x].push_back(y);
adj[y].push_back(x);
degree[x]++;
degree[y]++;
}
}
void DFS(int v){
visited[v]=true;
for(int x : adj[v]){
if(!visited[x]){
DFS(x);
3
}
}
}
bool isEuler(){
for(int i =1;i<=n;i++){
if(degree[i] %2 ==1){
return false;
}
}
int start = -1;
for(int i = 1;i<=n;i++){
if(degree[i]>0){
start= i;
break;
}
}
if(start == -1){
return true;
}
DFS(start);
for(int i = 1; i <=n;i++)
{
if(degree[i]>0 && !visited[i]){
return false;
}
}
return true;
}
int main() {
inp();
if(isEuler){
cout <<"yes";
}else {
cout << "no";
}
return 0;
}
Chu trình Hamilton:
int n,m;
set<int> adj[1001];
int degree[1001];
bool visited[1001];
4
int HC[1001];
void inp(){
cin >> n >> m;
for(int i =0 ; i <m;i++){
int x,y;
cin>>x>>y;
adj[x].insert(y);
adj[y].insert(x);
degree[x]++;
degree[y]++;
}
memset(visited,false,sizeof(visited));
}
bool check(){
for(int i = 1;i<=n;i++){
if(degree[i]< (n/2)){
return false;
}
}
return true;
}
void Hamilton(int pos, int u){
visited[u]=true;
HC[pos]=u;
if(pos == n){
if(adj[u].find(HC[1])!= adj[u].end()){
HC[++pos]=HC[1];
for(int k = 1;k<=pos;k++){
cout <<HC[k] << " ";
}
cout << endl;
}
return;
}
for(int v:adj[u]){
if(!visited[u]){
Hamilton(pos+1,v);
visited[v]=false;
}
}
visited[u]=false;
}
2. Đếm đồ thị (1)
Có bao nhiêu đồ thị vô hướng khác nhau có V đỉnh và E cạnh (không có cạnh song song)?
5
for(int i =0;i<v;i++){
if(!visited[i]){
visited[i]=true;
count+= countGraph(v,e-1,visited);
visited[i]=false;
}
}
return count;
}
4. Chu trình lẻ
Chứng minh rằng một đồ thị là đồ thị hai mầu (bipartite) khi và chỉ khi nó không chứa chu trình
độ dài lẻ. Đồ thị hai mầu là đồ thị mà có thể dùng hai mầu để tô mỗi đỉnh một mầu sao cho không
có cạnh nào nối giữa hai đỉnh cùng mầu.
Gợi ý: chứng minh bằng phản chứng.
5. Biconnected (1)
Một đồ thị được gọi là biconnected nếu mỗi cặp đỉnh đều được nối với nhau bởi hai đường đi
không giao nhau. Trong đồ thị liên thông, điểm articulation là đỉnh mà khi xóa nó và các cạnh kề
sẽ làm đồ thị mất tính liên thông. Hãy chứng minh rằng một đồ thị bất kì mà không có điểm
articulation là đồ thị biconnected.
Gợi ý: cho một cặp đỉnh s và t và một đường đi nối giữa chúng. Hãy sử dụng dữ kiện rằng không
có đỉnh nào trên đường đi đó là điểm articulation để xây dựng hai đường đi không giao nhau nối s
và t.
6
class Graph{
int V;
vector<vector<int>> adj;
void DFS(int v, vector<bool> visited);
public:
Graph(int V);
void addEdge(int v, int w);
bool isEdgeConnected();
};
Graph::Graph(int V){
this->V= V;
adj.resize(V);
}
void Graph::addEdge(int v, int w){
adj[v].push_back(w);
7
adj[w].push_back(v);
}
void Graph::DFS(int v, vector<bool> visited){
visited[v]=true;
for(int i: adj[v]){
if(!visited[i]){
DFS(i,visited);
}
}
}
bool Graph:: isEdgeConnected(){
for(int u =0;u<V;u++){
for(int v:adj[u]){
adj[u].erase(find(adj[u].begin(),adj[u].end(),v));
adj[v].erase(find(adj[v].begin(),adj[v].end(),u));
vector<bool> visited(V,false);
DFS(u,visited);
bool isConnect = true;
for(bool v:visited){
if(!v){
isConnect = false;
break;
}
}
adj[u].push_back(v);
adj[v].push_back(u);
if(!isConnect){
return false;
}
}
}
return true;
}
7. Xử lý ảnh
Hãy cài thuật toán floodfill trên ảnh để xác định các điểm ảnh kề nhau có cùng mầu.
Gợi ý: dựa DFS hoặc BFS
B. Đồ thị có hướng
Bởi vì BFS chỉ đánh dấu các đỉnh dựa trên khoảng cách đến root chứ không xác định được thứ tự
tô pô.
9. Chu trình Euler có hướng (1)
Viết một mô đun chương trình Euler nhận một đồ thị có hướng làm input và và tìm chu trình
Euler trong đồ thị đó hoặc báo là không tồn tại.
Gợi ý: Hãy chứng minh rằng một đồ thị có hướng G có một chu trình Euler khi và chỉ khi G liên
thông và mỗi đỉnh đều có bậc ra bằng bậc vào.
int n,m;
vector<int> adj[1001];
vector<int> in, out;
vector<bool> visited;
void inp(){
cin >> n >> m;
in.assign(n+1, 0);
out.assign(n+1, 0);
visited.assign(n+1, false);
bool isEuler(){
for(int i = 1; i <= n; i++){
if(in[i] != out[i]){
return false;
}
}
stack<int> st;
9
st.push(1);
visited[1] = true;
while(!st.empty()){
int x = st.top();
st.pop();
for(int t : adj[x]){
if(!visited[t]){
visited[t] = true;
st.push(t);
}
}
}
void printEuler(){
if(!isEuler()){
cout << "Khong ton tai chu trinh Euler trong do thi." << endl;
return;
}
vector<int> circuit;
dfs(1, circuit);
reverse(circuit.begin(), circuit.end());
for(int v : circuit){
cout << v << " ";
}
}
int main(){
inp();
printEuler();
}
Hãy mô tả một thuật toán thời gian tuyến tính tính thành phần liên thông mạnh chứa một đỉnh v
cho trước. Dựa trên thuật toán đó, hãy mô tả một thuật toán thời gian bậc hai đơn giản để tính các
thành phần liên thông mạnh của một đồ thị có hướng.
Gợi ý: dựa DFS
11. Đường đi Hamilton trong đồ thị có hướng phi chu trình (1)
Cho một đồ thị có hướng phi chu trình (DAG), thiết kế một thuật toán thời gian tuyến tính để xác
định xem có tồn tại một đường đi có hướng đi qua mỗi đỉnh đúng một lần hay không.
Gợi ý: Tính một sắp xếp tô pô và xem nếu có một cạnh nối giữa một cặp đỉnh liên tiếp trong thứ
tự tô pô
struct edge{
int u, v;
int w;
};
11
for(int i=0;i<m;i++){
if(numTrees == n) break;
edge e = canh[i];
if(Union(e.u,e.v)){
mst.push_back(e);
d+=e.w;
numTrees++;
}
}
if (numTrees != n) {
cout << "Rừng bao trùm nhỏ nhất không đủ số đỉnh" << endl;
} else {
cout << "Rừng bao trùm nhỏ nhất: " << d << endl;
for (auto it : mst) {
cout << it.u << " " << it.v << " " << it.w << endl;
}
}
}
struct Edge {
int u, v;
int w;
};
void make_set() {
for (int i = 1; i <= n; i++) {
parent[i] = i;
sz[i] = 1;
}
}
int find(int v) {
if (v == parent[v]) return v;
return parent[v] = find(parent[v]);
}
void inp() {
cin >> n >> m;
for (int i = 0; i < m; i++) {
int x, y, w;
cin >> x >> y >> w;
Edge e;
e.u = x;
e.v = y;
e.w = w;
edges.push_back(e);
}
}
void boruvka(){
vector<Edge> mst;
int d =0;
while(mst.size() < n-1){
vector<int> cheapest(n,-1);
for(auto e:edges){
int set1 = find(e.u);
int set2=find(e.v);
if (set1 != set2) {
if (cheapest[set1] == -1 || edges[cheapest[set1]].w > e.w) {
cheapest[set1] = e.u;
}
if (cheapest[set2] == -1 || edges[cheapest[set2]].w > e.w) {
cheapest[set2] = e.v;
}
}
if(mst.size()!= n-1) {
cout <<”đồ thị không liên thông” << endl;
}else{
15
void inp(){
cin >> n >> m >> s;
for(int i = 0; i < m; i++){
int x, y, w;
cin >> x >> y >> w;
adj[x].push_back({y, w});
adj[y].push_back({x, w});
}
}
while(!Q.empty()){
pair<int,int> top = Q.top();
Q.pop();
int u = top.second;
int kc = top.first;
int main(){
inp();
dijkstra(s);
return 0;
}
31. Tất cả các đường đi ngắn nhất trong đồ thị có chu trình âm (1)
Hãy chạy một phiên bản của thuật toán Bellman-Ford để xác định các trọng số pi[v] sao cho với
mỗi cạnh v→w, trọng số cạnh cộng với hiệu giữa pi[v] và pi[w] là không âm. Sau đó sử dụng các
trọng số này để đánh lại trọng số đồ thị, sao cho có thể sử dụng thuật toán Dijkstra để tìm tất cả
các đường đi ngắn nhất trong đồ thị mới.
Gợi ý: Hãy dãn cạnh theo thứ tự tăng dần của trọng số và tìm một đường đi tốt nhất; sau đó dãn
cạnh theo thứ tự giảm dần của trọng số và tìm một đường đi tốt nhất.
Gợi ý: Với mỗi đỉnh, tìm đường đi bitonic ngắn nhất đến đó sao cho các cạnh trọng số đang tăng
dần khi đến đỉnh đó bằng thuật toán Dijkstra. Từ đó, với mỗi đỉnh, tìm đường đi bitonic ngắn nhất
đến đó, sao cho các cạnh trọng số đã hết tăng và đang giảm dần khi đến đỉnh đó, cũng sử dụng
thuật toán Dijkstra.