一:无序字母对
欧拉回路,DFS遍历找到然后输出,注意利用欧拉回路的性质剪枝,否则超时。
#include<stdio.h>
#include<string.h>
#include<string>
#include<stdlib.h>
#include<queue>
#include<map>
#include<iostream>
#define Max 1000
using namespace std;
int a[60][60];//字母对对
int n;
int change(char temp)
{
if(temp>='a') //一定是小写
{
return temp-'a'+26;
}
return temp-'A';//返回小写字母
}
char black(int temp)//数字变成字母
{
if(temp<=25)
{
return temp+'A';
}
return 'a'+temp-26;
}
int dfs(int y,int num,string ans) //y 表示已经遍历到了第几个字母了。ans 是需要输出的字符
{
if(num==n+1)
{
cout<<ans<<endl;
return 1;
}
for(int i=0;i<52;i++)
{
if(a[y][i])//1
{
a[y][i]=0;
a[i][y]=0;
if(dfs(i,num+1,ans+black(i)))
{
return 1;
}
a[y][i]=1;
a[i][y]=1;
}
}
return 0;
}
int m[60];//保持度数
int main()
{
scanf("%d",&n);
getchar();
char x,y,lajij;
int x1,x2,y1,y2;
for(int i=0;i<n;i++)
{
cin>>x>>y;
x1=change(x);
y1=change(y);
a[x1][y1]=1;
a[y1][x1]=1;
m[x1]++; //记录度数
m[y1]++; //记录度数
}
int cnt=0;
int h=0;
for(int i=0;i<52;i++)
{
if(m[i]&1) // 查找基数点 的个数
{
cnt++;
if(!h)
h=i+1;
}
}
if(!h) //如果不存在基数点
{
for(int i=0;i<52;i++)
{
if(m[i])
{
h=i;break;
}
}
}
if(cnt&&cnt!=2) //存在但是 ,基数点不为0
{
printf("No Solution\n");
return 0;
}
h--;
for(int j=0;j<52;j++) // 根据找到的h作为起点搜索
{
if(a[h][j])
{
char laji[3];
a[h][j]=0;
a[j][h]=0;
x=black(h);
y=black(j);
laji[0]=x;
laji[1]=y;
laji[2]='\0';
string temp;
temp=laji;
if(dfs(j,2,temp))
{
return 0; //找到,在dfs里面输出
}
a[h][j]=1;
a[j][h]=1;
}
}
printf("No Solution\n");
return 0;
}
剪枝看题解的,有点不理解的是为什么只需要判断一个h就可以了。。。。eee
二: [USACO08DEC]在农场万圣节Trick or Treat on the Farm
图的遍历,图中有各个环、且环上还有链。图可能被分成多个块。
用 Tarjan写? 额,我好像不会。。。
首先DFS跑一遍,过了一组数据,时间没超,内存超了,可能爆栈了。
然后把递归转化成循环190msAC;
递归代码都没删的。-_-||
注释在代码里面
#include<stdio.h>
#include<string.h>
#include<string>
#include<stdlib.h>
#include<queue>
#include<map>
#include<stack>
#define Max 100010
using namespace std;
int a[Max];//穿越的栏杆
int m[Max];//已经走过的答案
int flag[Max];//是否走过
queue<int> q;
/*递归超时??*/
int dfs(int i,int num,int begin)//递归的时候记得把这条线上所有的点都更新.bengim,记录是否存在环
{
int this_ans=0;
if(i==begin)//存在环
{
int now=i;
m[i]=num;
i=a[i];
while(i!=now) //环全部刷新
{
m[i]=num;
i=a[i];
}
return num;
}
if(m[i]) //已经保存过了
{
return m[i]+num;
}
this_ans = dfs(a[i],num+1,begin); //跑一遍DFS
if(!m[i]) //不是环,自己还没保存的
{
m[i]=this_ans;
}
return this_ans;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++)
{
flag[i]=1;//自己走过
if(m[i]) continue;
if(m[a[i]])
m[i]=m[a[i]]+1;
else //新的点只有两种情况,一种是在环上,一种是在环上的链上
{
//每个新点都是存在有环的回路
int num=1; //这个是开始默认经过自己,代表点数
q.push(i); //当前节点进入
int j=i,p; //j表示已经走到第几个点了 ,p作为临时变量
while(!flag[a[j]]&&!m[a[j]]) //下个节点是否走过,注意在m[]里面也判断
{
j=a[j];
flag[j]=1;
q.push(j);
num++;
}
if(m[a[j]])//如果是下个节点保存过了,说明点在链上,且环已经全部保存过了
{
num+=m[a[j]]; //把环的结果保存,链上点的答案依次递减
while(q.size())
{
p=q.front();
m[p]=num;
num--;
q.pop();
}
continue;
}
//环、链都没有保存过
while(q.size()) //把环外的点的全部保存
{
p=q.front();
if(p!=a[j]) //找到圈的位置
{
m[p]=num;
num--;
}
else
break;
q.pop(); //pop,应该放这里,因为圈上的点被弹出来,判断
}
while(q.size())//圈内答案相同,等于圈的大小
{
p=q.front();
q.pop();
m[p]=num;
}
}
}
for(int i=1;i<=n;i++)
{
printf("%d\n",m[i]);
}
return 0;
}
今天水了一天!明天加油!