B - B
一张无向图,给边指定方向,问最多可以让多少个点度数为0,输出方案。
考虑欧拉回路性质:度数为偶数的点一定可以变成为0,对于度数为奇数的点,将每个点向0连一条边,度数为奇数的点一定有偶数个,
构造一个欧拉回路,直接用set保存输出。dfs删除对应的边。
#include<bits/stdc++.h> using namespace std; const int N=8e3+5; #define pb push_back int ecnt,n,m; int degree[N]; set<int>G[N]; vector<int>V; vector<pair<int,int> >ans; void init(){ for(int i=1;i<=n;i++)degree[i]=0; V.clear();ans.clear(); } void dfs(int u){ while(G[u].size()){ int v=*G[u].begin(); ans.pb(make_pair(u,v) ); G[u].erase(v);G[v].erase(u); dfs(v); } } int main(){ int t;scanf("%d",&t); while(t--){ scanf("%d %d",&n,&m); init(); for(int i=1,u,v;i<=m;i++){ scanf("%d %d",&u,&v); G[u].insert(v);G[v].insert(u); degree[u]++;degree[v]++; } int cur=0; for(int i=1;i<=n;i++){ if(degree[i]%2==0)cur++; else V.pb(i); } for(int i=0;i<V.size();i++){ G[0].insert(V[i]);G[V[i]].insert(0); } for(int i=1;i<=n;i++)dfs(i); printf("%d\n",cur); for(int i=0;i<ans.size();i++){ if(ans[i].first&&ans[i].second){ printf("%d %d\n",ans[i].first,ans[i].second); } } } // system("pause"); return 0; }
F - F
题意:DAG问多少个多余的边。
考虑保存每个点的前驱。当枚举到当前边时,如果之前已经有点访问过了,说明当前边是多余的。
用bitset维护,复杂度为O(n*n/32)
#include <bits/stdc++.h> #include <bitset> using namespace std; const int N=2e4+50; int n,m; int in[N]; vector<int>G[N],pre[N],top; bitset<N>bit[N]; void init(){ for(int i=1;i<=n;i++)pre[i].clear(),in[i]=0,G[i].clear(); top.clear(); } void topo(){ queue<int>Q; for(int i=1;i<=n;i++)if(in[i]==0){Q.push(i);top.push_back(i);} while(!Q.empty()){ int u=Q.front();Q.pop(); top.push_back(u); for(int i=0;i<G[u].size();i++){ int v=G[u][i]; if(--in[v]==0)Q.push(v); pre[v].push_back(u); } } } int main(){ int t;scanf("%d",&t); while(t--){ scanf("%d %d",&n,&m); init(); for(int i=1,u,v;i<=m;i++){ scanf("%d %d",&u,&v); G[u].push_back(v); in[v]++; } topo(); int ans=0; for(int i=1;i<=n;i++)bit[i].reset(),bit[i].set(i); for(int i=0;i<top.size();i++){ int u=top[i]; for(int j=pre[u].size()-1;j>=0;j--){ int v=pre[u][j]; if(bit[u][v])ans++; bit[u]|=bit[v]; } } printf("%d\n",ans); } // system("pause"); return 0; }