总结:
(1)图论的dfs还有些不熟练,需要加强练习。
(2)多学学STL。
思路:
已知一个点,将它的向下和对角线的元素标记好就行了,然判断接下来的点是否标记过了。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1005;
int mp[maxn][maxn];
int main(void)
{
int n,k,i,x,fg,j;
scanf("%d",&k);
while(k--){
scanf("%d",&n);fg=0;
memset(mp,0,sizeof(mp));
for(i=1;i<=n;i++){
scanf("%d",&x);
if(fg==0&&mp[i][x]==0)
for(j=i;j<=n;j++){
mp[j][x]=1;
if(x+(j-i)<=n) mp[j][x+j-i]=1;
if(x-(j-i)>=1) mp[j][x-j+i]=1;
}
else fg=1;
}
if(fg==1) printf("NO\n");
else printf("YES\n");
}
return 0;
}
思路:这次的排序是输出前k个或小于k个“最大的值”,一开始我想用优先队列去做,但是每次都要入队,出队,很耗时;
就超时了。
做法一:
将前k个或小于k个数字排序。(参考文章)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100100;
struct Node{
int num,id;
bool operator <(Node a) const{
if(num!=a.num) return num>a.num;
else return id<a.id;
}
}cur[120];
int vis[maxn];
int main(void)
{
Node tmp;
int n,k,i,j,x,y,pos=0,fg;
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++){
scanf("%d",&x);
tmp.id=x;tmp.num=++vis[x];
if(i==1) cur[++pos]=tmp;
else{
printf("%d:",x);
sort(cur+1,cur+1+pos);
if(pos<k){
fg=0;
for(j=1;j<=pos;j++){
printf(" %d",cur[j].id);
if(cur[j].id==x) cur[j]=tmp,fg=1;
}
if(fg==0) cur[++pos]=tmp;
}
else{
fg=0;
for(j=1;j<=pos;j++){
printf(" %d",cur[j].id);
if(cur[j].id==x) cur[j]=tmp,fg=1;
}
if(fg==0&&(cur[pos].num<tmp.num||(cur[pos].num==tmp.num&&cur[pos].id>tmp.id))) cur[pos]=tmp;
}
printf("\n");
}
}
return 0;
}
做法二:
用set做,因为set中所有元素都是唯一的,而且根据大小排序,就很方便。(参考文章)
#include<iostream>
#include<cstdio>
#include<set>
using namespace std;
const int maxn = 100100;
struct Node{
int id,num;
bool operator <(Node a) const{
if(num!=a.num) return num>a.num;
else return id<a.id;
}
}cur[120];
int vis[maxn]={0};
int main(void)
{
int n,k,i,j,x,y;
set <Node> st;
Node tmp;
scanf("%d%d",&n,&k);
for(i=0;i<n;i++){
scanf("%d",&x);
tmp.id=x;tmp.num=vis[x];
if(i){
printf("%d:",x);
j=0;
for(auto it=st.begin();j<k&&it!=st.end();it++,j++) printf(" %d",it->id);
printf("\n");
}
auto it=st.find(tmp);
if(it!=st.end()) st.erase(it);
vis[x]++;tmp.num=vis[x];
st.insert(tmp);
}
return 0;
}
思路:加括号的条件是左,右子树中有一个节点非空即可,但是最后要去掉两遍的括号即可。
(一开始没想到怎么找根节点,就找最长的str,从根节点遍历得到的str最长,后来想想,在输入的时候标记出现的儿子节点就行了,没被标记的节点一定是根节点)。
注意:如果节点只有一个要特殊判断一下。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
const int maxn = 100100;
string ss[maxn];
struct Node{
int id,le,ri;
}cur[maxn];
int n,vis[maxn];
string str;
void inorder(int x)
{
if(x!=-1){
if(cur[x].le!=-1||cur[x].ri!=-1) str+='(';
inorder(cur[x].le);
str+=ss[x];
inorder(cur[x].ri);
if(cur[x].le!=-1||cur[x].ri!=-1) str+=')';
}
}
int main(void)
{
int i,j,x,y,len;
string op;
scanf("%d",&n);
for(i=1;i<=n;i++){
cin>>op;
scanf("%d%d",&x,&y);
ss[i]=op;
cur[i].id=i;cur[i].le=x;cur[i].ri=y;
}
string tsp="";
if(n==1){
cout<<ss[1]<<endl;
return 0;
}
for(i=1;i<=n;i++){
str="";
inorder(i);
if(str.length()>tsp.length()) tsp=str;
}
for(i=1,len=tsp.length();i<len-1;i++) printf("%c",tsp[i]);
return 0;
}
思路:这道题一开始用bfs,然后要判断的结果太多了就卡住了。
参考了柳神的文章,可以再深搜时记录要求的信息(经过的节点,转弯的次数,并且记录路径),
转弯路径没法直接dfs找出,就从已知的路径中找转弯的次数就好了,记录节点的边可以用line(x*n+y)这种方式记录,
也可以用二维数组记录,注意,路径要提前记录st节点。
反思:
(1)所求数据过多时,可以通过一次dfs同时更新不同数据,并且利用已有数据求出未知数据。
(2)二位数组可以开到10000*10000,vector数据可以pop_back()。
(3)深搜完要回溯,返还数据。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<string>
using namespace std;
const int maxn = 100100;
const int INF = 99999999;
int vis[maxn],dis[maxn],st,ed,micnt,mitran;
vector <int> vc[10001],path,tmpath;
map <int,int> line;
int tran(vector <int> vv)
{
int i,v,pre=0,cnt=0;
for(i=1;i<vv.size();i++){
if(pre!=0&&line[vv[i-1]*10000+vv[i]]!=pre) cnt++;
pre=line[vv[i-1]*10000+vv[i]];
}
return cnt;
}
void dfs(int u,int cnt)
{
if(u==ed&&(cnt<micnt||(cnt==micnt&&tran(tmpath)<mitran))){
path=tmpath;
micnt=cnt;
mitran=tran(tmpath);
}
if(u==ed) return ;
for(int i=0;i<vc[u].size();i++){
int v=vc[u][i];
if(!vis[v]){
vis[v]=1;
tmpath.push_back(v);
dfs(v,cnt+1);
vis[v]=0;
tmpath.pop_back();
}
}
}
int main(void)
{
int n,m,k,i,j,x,y;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&m);
for(j=1;j<=m;j++){
scanf("%d",&x);
if(j==1) y=x;
else{
vc[x].push_back(y);
vc[y].push_back(x);
line[x*10000+y]=line[y*10000+x]=i;
y=x;
}
}
}
scanf("%d",&k);
while(k--){
scanf("%d%d",&st,&ed);
mitran=INF;micnt=INF;
memset(vis,0,sizeof(vis));
tmpath.clear();
tmpath.push_back(st);
vis[st]=1;
dfs(st,0);
x=0;y=st;
printf("%d\n",micnt);
for(i=1;i<path.size();i++){
if(line[path[i-1]*10000+path[i]]!=x){
if(x!=0) printf("Take Line#%d from %04d to %04d.\n",x,y,path[i-1]);
x=line[path[i-1]*10000+path[i]];
y=path[i-1];
}
}
printf("Take Line#%d from %04d to %04d.\n",x,y,ed);
}
return 0;
}