拓扑排序
输出字典序最小的拓扑排序
有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。
bool mp[MAXN][MAXN];
int input[MAXN]; //入度
priority_queue<int,vector<int>,greater<int> >q;
int n,m;
void work(int n){
for(int i=1;i<=n;i++){
if(input[i] == 0){ //把入度为0的点放进去
q.push(i);
}
}
int p=1;
while(!q.empty()){
int now = q.top();
q.pop();
if(p != n){
cout << now << " ";
p++;
}
else cout << now << endl;
for(int i=1;i<=n;i++){
if(!mp[now][i])continue;
input[i] --;
if(input[i] == 0)q.push(i);
}
}
}
void init(){
memset(mp,0,sizeof(mp));
memset(input,0,sizeof(input));
}
int main(){
while(cin >> n >> m){
init();
int x,y;
while(m--){
cin >> x >> y;
if(!mp[x][y]){
mp[x][y] = 1;
input[y] ++;
}
}
work(n);
}
return 0;
}
[欧拉回路]题目
欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个图,问是否存在欧拉回路?
无向图:
1.全是偶点,存在欧拉回路
2.只有两个奇点,存在欧拉路有向图:
把一个点出度为1,入度为-1,欧拉回路度数全为零,欧拉通路只有一个1,一个-1,其他都是0;
vector<int>e[MAXN];
int vis[MAXN];
int n,m;
void init(){
for(int i=0;i<MAXN;i++)e[i].clear();
memset(vis,0,sizeof(vis));
}
void dfs(int x){ //判断联通
int n = e[x].size();
vis[x] = 1;
for(int i=0;i<n;i++){
int now = e[x][i];
if(vis[now] == 0){
vis[now] = 1;
dfs(now);
}
}
}
int main(){ //判断是否存在欧拉回路
//联通且都是偶点
while(cin >> n && n){
cin >> m;
init();
while(m--){
int x,y;
cin >> x >> y;
e[x].push_back(y);
e[y].push_back(x);
}
dfs(1); //找联通
int i;
for(i=1;i<=n;i++){
if(!vis[i] || (e[i].size() & 1) )break; //不连通或者有奇点
}
if(i != n+1){
cout << "0" << endl;
continue;
}
cout << "1" << endl;
}
return 0;
}
hdu1116 play on words
把单词首尾连起来,然后看能不能连成一行
[思路]:先用并查集是否连通,然后用点的入度出度判断是否是欧拉路径.(可以是环)
int fa[30],in[30],out[30];
bool vis[30];
int find_set(int x){return fa[x] == x?x:fa[x] = find_set(fa[x]);}
void merge_set(int x,int y){
x = find_set(x);
y = find_set(y);
if(x != y){fa[x] = y;}
}
int cc;
string s;
int main(){
cin >> cc;
while(cc--){
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(vis,0,sizeof(vis));
for(int i=1;i<MAXN;i++)fa[i] = i;
int n;cin >> n;
while(n--){
cin >> s;
int lena = s.length();
int l = s[0]-'a'+1;
int r = s[lena-1]-'a'+1;
out[l]++;in[r]++;
vis[l] = 1;vis[r] = 1;
merge_set(l,r);
}
int root=0,inin=0,ouou=0,f = 1;
for(int i=1;i<MAXN;i++){
if(vis[i]){
if(fa[i] == i)root ++;
if(in[i] != out[i]){
if(in[i] - out[i] == 1)inin++;
else if(out[i] - in[i] == 1)ouou++;
else f = 0;
}
}
if(root > 1){
f = 0;
break;
}
}
if((f && (inin==0) && (ouou==0)) || (f && (inin == 1) && (ouou == 1))){
cout << "Ordering is possible." << endl;
}
else cout << "The door cannot be opened." << endl;
}
return 0;
}
深搜优先生成树求割点
在一个连通分量G中,对任意一个点s做DFS,能访问到所有点,产生一棵“深搜优先生成树”T。定理1:T的根结点s是割点,当且仅当s有2个或更多的子结点。
定理2:T的非根结点u是割点,当且仅当u存在一个子结点v,v及其后代都没有回退边连回u的祖先。