Deepest Root
题目大意就是如果图是连通的,输出最深的树的根结点的并集;否则输出错误信息。
思路:
先用DFS判断连通分量个数,如果是1个表示图连通,此时tmp也记录了所有最深的根结点,然后随便取一个(这里取了第一个)再次DFS,两次并起来就是结果。
//
// @author prime on 2017/6/8.
//
#include
#include
#include
using namespace std;
int N;
vector<vector<int>> G;//邻接表。不能用邻接矩阵因为太大了超内存
vector<int> tmp;//记录根节点的集合
set<int> res;
bool visited[10001];
int max_depth=-1;
void DFS(int u,int depth)
{
visited[u]= true;
if(depth>max_depth)
{
max_depth=depth;
tmp.clear();
tmp.push_back(u);
} else if(depth==max_depth)
{
tmp.push_back(u);
}
for (int i=0;iif(!visited[G[u][i]])
{
DFS(G[u][i],depth+1);
}
}
}
int main()
{
fill(visited,visited+10001, false);
scanf("%d",&N);
G.resize(N+1);
for (int i=0;i1;++i)
{
int u,v;
scanf("%d %d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
int cc=0;//连通分量个数
int begin;//记录第一次DFS后tmp的第一个元素,后面以此为起点再次DFS。二次DFS并集就是所有的结果(一次可能会漏解)
/*判断连通分量*/
for (int i=1;i<=N;++i)
{
if(!visited[i])
{
DFS(i,1);
cc++;
if(i==1)
{
for (int j=0;jif(j==0)
begin=tmp[j];
}
}
}
}
if(cc>1)
printf("Error: %d components",cc);
else
{
fill(visited,visited+N+1, false);
tmp.clear();
//max_depth=0;
DFS(begin,1);
for (int i=0;ifor (set<int>::iterator it=res.begin();it!=res.end();it++)
printf("%d\n",*it);
}
return 0;
}
Digital Library
思路:
程序目的是查询,即输入有关信息,输出相应信息。由此,这里依旧沿用用空间换时间的战术,对每个查询信息建立对应的键值~
//
// @author prime on 2017/6/8.
//
#include
#include
#include
using namespace std;
map<string,set<int>> Title,Author,Keywords,Publisher,Year;
void query(const map<string,set<int>> &s,string &query_str);
int main()
{
int N,M;
cin>>N;
string title,author,keywords,publisher,year;
int id;
for (int i=0;icin>>id;
getchar();//读取换行符
getline(cin,title);
Title[title].insert(id);
getline(cin,author);
Author[author].insert(id);
while (cin>>keywords)
{
Keywords[keywords].insert(id);
char c=getchar();//读取字符,提升到int后返回,这样可以容纳EOF等特殊值
if(c=='\n')
break;
}
/*getline(cin,keywords);
for (string & e:split(keywords,' '))
{
Keywords[e].insert(id);
}*/
getline(cin,publisher);
Publisher[publisher].insert(id);
getline(cin,year);
Year[year].insert(id);
}
string query_str;
int num;
cin>>M;
for (int i=0;iscanf("%d: ",&num);
getline(cin,query_str);
cout<": "<"\n";
if(num==1)
{
query(Title,query_str);
} else if(num==2)
query(Author,query_str);
else if(num==3)
query(Keywords,query_str);
else if(num==4)
query(Publisher,query_str);
else if(num==5)
query(Year,query_str);
}
return 0;
}
void query(const map<string,set<int>> &s,string &query_str)
{
map<string,set<int>>::const_iterator it=s.find(query_str);//find返回迭代器,其指向一个pair,pair.first==key
if(it==s.cend())
{
printf("Not Found\n");
} else
{
for (auto &e:it->second)//set可以直接这样遍历,用迭代器也行。基于范围的for循环本质上可以运用于任何拥有begin和end成员的序列
printf("%07d\n",e);//必须7位,我就艹了!
}
}
Have Fun with Numbers
思路:
就是把输入的数翻倍,之后看输入的每一位是否在输出中都出现了且出现次数一样。
//
// @author prime on 2017/6/11.
//
#include
#include
using namespace std;
int main()
{
int set[10];
fill(set,set+10,0);
string num;
cin>>num;
int res[num.size()+1];
fill(res,res+num.size()+1,0);
for (int i=num.size()-1;i>=0;i--)
{
num[i]-='0';
set[num[i]]++;
num[i]*=2;
res[i+1]+=num[i];
if(num[i]>9)
{
res[i]+=num[i]/10;
res[i+1]%=10;
}
}
//cout<<"length="<
for (int i=0;i1 ;++i)
{
if(i==0&&res[i]==0)
continue;
if(set[res[i]]>0)
set[res[i]]--;
else
{
printf("No\n");
goto NO;
}
}
printf("Yes\n");
NO:
for (int i=0;i1;++i)
{
if(i==0&&res[i]==0)
{
continue;
}
printf("%d",res[i]);
}
return 0;
}
Palindromic Number
题目是非常经典的回文数问题。
思路:解决这个问题的最快方法是用string,而不是用数组。因为有内建的reverse
函数,很方便。
//
// @author prime on 2017/6/11.
//
#include
#include
using namespace std;
void add(string &a,string &b)
{
string res(a.size(),0);
int carry=0;//是否进位
for (int i=a.size()-1;i>=0;i--)
{
res[i]=a[i]+b[i]-'0'+carry;
carry=0;
if(res[i]>'9')
{
carry=1;
res[i]-=10;
}
}
if(carry)
res='1'+res;
a=res;
}
int main()
{
int K;
string in;
cin>>in>>K;
for (int i=0;istring b=in;
reverse(b.begin(),b.end());
if(b==in)
{
cout<'\n'<return 0;
}
add(in,b);
}
cout<"\n"<return 0;
}
下面是数组版的,有一个用例过不去:
//
// @author prime on 2017/6/11.
//
#include
#include
using namespace std;
bool is_palindromic(const vector<int> &a)
{
bool flag=true;
if(a.size()==1)
return true;
for (auto pre=a.cbegin(),it=a.cend()-1;pre!=it;pre++,it--)
{
if(*pre!=*it)
{
flag= false;
break;
}
}
return flag;
}
void add(vector<int> &a)
{
auto it=a.begin(),re=a.end()-1;
vector<int> tmp;
while (it!=a.end())
{
tmp.push_back(*it+*re);
it++;re--;
}
for (int i=tmp.size()-1;i>0;--i)
{
if(tmp[i]>9)
{
tmp[i-1]+=tmp[i]/10;
tmp[i]%=10;
}
}
if(tmp[0]>9)
{
tmp.insert(tmp.begin(),0);
tmp[0]=tmp[1]/10;
tmp[1]%=10;
}
a=tmp;
}
int main()
{
string input;
int k;
cin>>input>>k;
vector<int> a;
for (auto & e:input)
{
a.push_back(e-'0');
}
int total=0;
for (int i=0;iif(is_palindromic(a))
goto YES;
add(a);
total++;
}
for (auto &e:a)
cout<cout<<'\n'<return 0;
YES:
for (auto &e:a)
cout<cout<<'\n'<return 0;
}
PAT Ranking
思路:类似的排序题前面已经做过不少了,这里也一样。先局部小排,再全局大排。
这种题不是很难,但要细心,什么时候可以合并步骤什么时候不行,得清楚。
//
// @author prime on 2017/6/11.
//
#include
#include
#include
using namespace std;
struct Testee
{
string id;
int local_num;
int local_rank;
int score;
int total_rank;
};
bool cmp(const Testee& s1, const Testee &s2)
{
return s1.score==s2.score?s1.ids2.score;
}
int main()
{
int N,K;
cin>>N;
vector res;
int total=0;
for (int i=0;icin>>K;
total+=K;
Testee tmp;
for (int j=0;jcin>>tmp.id>>tmp.score;
res.push_back(tmp);
}
/*局部排序*/
sort(res.end()-K,res.end(),cmp);
res[total-K].local_rank=1;
res[total-K].local_num=i+1;
for (int j=1;j1;
if(res[total-K+j].score==res[total-K+j-1].score)
{
res[total-K+j].local_rank=res[total-K+j-1].local_rank;
continue;
} else
{
res[total-K+j].local_rank=j+1;
}
}
}
sort(res.begin(),res.end(),cmp);
cout<0].total_rank=1;
for (int i=1;i//这一步不能省,起初想法直接输出排名,但是需要考虑可能有多于2个成绩一样的情况,遂两个用例过不去
if(res[i].score==res[i-1].score)
{
res[i].total_rank=res[i-1].total_rank;
}
else
res[i].total_rank=i+1;
}
for (auto &e:res)
{
cout<" "<" "<" "<return 0;
}
Table Tennis
思路:参照以往银行排队问题,通过记录每个桌子最早结束时间来判断下一桌。时间依旧化成秒统一计算。主循环遍历人,根据下一桌和当前人是否vip分为四种情况:
//
// @author prime on 2017/6/12.
//
#include
#include
#include
using namespace std;
struct Table
{
int over_time;//结束时间
int serve_count;//服务人数
int tag;//VIP桌?
};
struct People
{
int arrive_time;
int tag;
int serve_time;//开始服务时间
int play_time;//玩了多久
};
int N,K,M;
vector p;
vector t;//K张桌子1~K
bool cmp(const People& o1,const People& o2)
{//根据到达时间进行排序
return o1.arrive_timebool cmp2(const People& o1,const People& o2)
{//根据服务开始时间进行排序
return o1.serve_timeint Find_next_vip(int vip)
{
vip++;
for (;vip!=p.size()&&p[vip].tag==0;vip++);
return vip;
}
void Allocate_table(int current,int point)
{
if(p[current].arrive_timeelse
{
p[current].serve_time=p[current].arrive_time;
}
t[point].over_time=p[current].play_time+p[current].serve_time;
t[point].serve_count++;
}
int main()
{
scanf("%d",&N);
People tmp;
for (int i=0,h,m,s,play;iscanf("%d:%d:%d %d %d",&h,&m,&s,&play,&tmp.tag);
tmp.arrive_time=h*3600+m*60+s;
if(tmp.arrive_time>=21*3600)
continue;
tmp.serve_time=21*3600;//表示还没有被计算过
tmp.play_time=play<120?play*60:7200;//最多2小时
p.push_back(tmp);
}
scanf("%d %d",&K,&M);
t.resize(K+1);
for (auto & e:t)//桌子们初始化
{
e.over_time=8*3600;//一开始所有桌子的结束时间初始化8时
e.serve_count=0;
e.tag=0;
}
for (int i=1,num;i<=M;i++)
{
scanf("%d",&num);
t[num].tag=1;
}
sort(p.begin(),p.end(),cmp);//按照来的顺序排队
int current=0,vip_index=-1;//当前队列的索引,下一个vip的索引
vip_index=Find_next_vip(vip_index);
while(current//对队伍进行遍历
int point=0,min_end_time=999999;
for (int i=1;i<=K;++i)
{//用point指向最快结束的一桌
if(t[i].over_timeif(min_end_time>=21*3600)//打烊了,不再接待新顾客
break;
if(p[current].tag==1&¤t//中间优先安排的要过滤掉
current++;
continue;
}
if(t[point].tag==1)
{//下一个是vip桌
if(p[current].tag==1)
{//正好下一个人是VIP
Allocate_table(current,point);
vip_index=Find_next_vip(vip_index);
current++;
}
else
{
if(vip_index//如果队伍后面还有vip则优先安排它到这个桌子
Allocate_table(vip_index,point);
vip_index=Find_next_vip(vip_index);
} else
{
Allocate_table(current,point);
current++;
}
}
}
else
{//下一桌不是VIP桌
if(p[current].tag==0)
{//下一个人也不是VIP
Allocate_table(current,point);
current++;
} else
{//下一个人是VIP
int vip_point=-1,min_vip_end_time=99999999;
for (int i=1;i<=K;++i)
{
if(t[i].tag==1&&t[i].over_time//先在vip桌中找,找不到就当作普通客人安排
if(vip_point!=-1&&p[current].arrive_time>=min_vip_end_time)
Allocate_table(current,vip_point);
else
Allocate_table(current,point);
vip_index=Find_next_vip(vip_index);//更新下一个vip
current++;
}
}
}
sort(p.begin(),p.end(),cmp2);
for (int i=0;i21*3600;i++)
{
printf("%02d:%02d:%02d ",p[i].arrive_time/3600,p[i].arrive_time%3600/60,p[i].arrive_time%60);
printf("%02d:%02d:%02d ",p[i].serve_time/3600,p[i].serve_time%3600/60,p[i].serve_time%60);
printf("%.0f\n",round((p[i].serve_time-p[i].arrive_time)/60.0));
}
for (int i=1;i<=K;++i)
{
printf("%d",t[i].serve_count);
if(i!=K)
printf(" ");
}
return 0;
}
1027[进制转换]
Colors in Mars
思路:简单的进制转换问题,难度不大。细心就好。
//
// @author prime on 2017/6/12.
//
#include
#include
using namespace std;
char map[13]={'0','1','2','3','4','5','6','7','8','9','A','B','C'};
vector<int> convert(int a)
{
vector<int> res;
res.push_back(a/13);
res.push_back(a%13);
return res;
}
int main()
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
vector<int> A=convert(a),B=convert(b),C=convert(c);
printf("#%c%c%c%c%c%c",map[A[0]],map[A[1]],map[B[0]],map[B[1]],map[C[0]],map[C[1]]);
return 0;
}
1028[排序]
List Sorting
思路:就是简单的排序,不过,最后一个用例很大,用string保存name会超时的。本以为用cin慢,关闭同步、换scanf都不好使。换成char数组就过了 ,太坑了吧?
如果不是这里限制,一般id这种都限制几位,用string较为方便,用整型输出时一定记住格式!看是否需要补全。
//
// @author prime on 2017/6/13.
//
#include
#include
#include
#include
using namespace std;
struct Student
{
int id;
char name[10];
int score;
};
bool cmp_id(const Student& o1, const Student& o2)
{
return o1.idbool cmp_name(const Student& o1,const Student&o2)
{
//return o1.name!=o2.name?o1.name
return strcmp(o1.name,o2.name)<=0;
}
bool cmp_score(const Student&o1,const Student&o2)
{
//return o1.score!=o2.score?o1.score
return o1.score<=o2.score;
}
//最后一个测试点超大,string会超时。。。
int main()
{
int N,C;
scanf("%d%d",&N,&C);
vector s(N);
for (int i=0;iscanf ("%d %s %d",&s[i].id,s[i].name,&s[i].score);
}
switch (C)
{
case 1:
sort(s.begin(),s.end(),cmp_id);
break;
case 2:
sort(s.begin(),s.end(),cmp_name);
break;
case 3:
sort(s.begin(),s.end(),cmp_score);
break;
}
for (int i=0;iprintf ("%06d %s %d\n",s[i].id,s[i].name,s[i].score);
}
return 0;
}
1029[两个指针]
Median
思路:假设两个序列长度m,n,找到中位数就是去掉(m+n-1)/2
个数字即可。所有就用两个指针,一直剃掉元素。这里的题目意思是上中位数。
//
// @author prime on 2017/6/13.
//
#include
#include
using namespace std;
int main()
{
int n1,n2;
scanf("%d",&n1);
vector<long int> a(n1);
for (int i=0;iscanf("%ld",&a[i]);
scanf("%d",&n2);
vector<long int> b(n2);
for (int i=0;iscanf("%ld",&b[i]);
auto p1=a.cbegin(),p2=b.cbegin();
int count=(n1+n2-1)/2;//舍弃这么多的数字
while(count!=0)
{
if(p1==a.cend())
{
p2++;
goto next;
}
if(p2==b.cend())
{
p1++;
goto next;
}
if(*p1<=*p2)
p1++;
else
p2++;
next:
count--;
}
long res;
if(p1!=a.cend()&&p2!=b.cend())
res=*p1>*p2?*p2:*p1;
else
res=p1==a.cend()?*p2:*p1;
printf("%ld",res);
return 0;
}
1030[Dijkstra+DFS]
Travel Plan
又到了图论,好消息是PAT的图论题套路差不多,和之前的自行车调度问题很像;坏消息是模板我还是记不住/(ㄒoㄒ)/~~。
思路:
首先计算最短路径,对每个结点来说,记录离它最近的前驱结点,如果两个距离都一样是最近的,那么就都记录进去。然后从终点开始,逆向DFS(有点回溯的味道),主要针对所有的前驱结点,一边前进一边记录路径。直到到达起始结点后,对路径的所有的结点计算总费用,如果总费用小于全局变量min_cost就更新它,并把当前路径拷贝给path。(DFS时无需再用visited数组,因为到达起点就是结束)
//
// @author prime on 2017/6/15.
//
#include
#include
using namespace std;
const int inf=99999999;
int G[510][510];
int cost[510][510];
int dist[510];
bool visited[510];
int N,M,S,D;
vector<int> pre[510];
vector<int> path,tmp_path;
int min_cost=inf,tmp_cost;
void DFS(int u);
int main()
{
/*初始化各种变量*/
fill(visited,visited+510, false);
fill(G[0],G[0]+510*510,inf);
fill(dist,dist+510,inf);
scanf("%d%d%d%d",&N,&M,&S,&D);
for (int i=0,u,v;iscanf("%d %d",&u,&v);
scanf("%d %d",&G[u][v],&cost[u][v]);
G[v][u]=G[u][v];
cost[v][u]=cost[u][v];
}
dist[S]=0;
pre[S].push_back(S);
for (int i=0;iint min_dist=inf,u=-1;
for (int j=0;jif(!visited[j]&&min_dist>dist[j])
{
min_dist=dist[j];
u=j;
}
}
if(u==-1)
break;
visited[u]=true;
for (int v=0;vif(!visited[v]&&G[u][v]!=inf)
{
if(dist[v]>dist[u]+G[u][v])
{
pre[v].clear();
pre[v].push_back(u);
dist[v]=dist[u]+G[u][v];
} else if(dist[v]==dist[u]+G[u][v])
{
pre[v].push_back(u);
}
}
}
}
//fill(visited,visited+N, false);
DFS(D);
for (int i=path.size()-1;i>=0;--i)
printf("%d ",path[i]);
printf("%d %d",dist[D],min_cost);
return 0;
}
void DFS(int u)
{
//visited[u]=true;
if(u==S)
{//从终点已经回到起点
tmp_path.push_back(u);
tmp_cost=0;
for (int i=tmp_path.size()-1;i>0;i--)
{//从源点到目的结点的路径
int index=tmp_path[i];
int next_index=tmp_path[i-1];
tmp_cost+=cost[index][next_index];
}
if(tmp_costelse
{
tmp_path.push_back(u);
for (int i=0;i