1013 Battle Over Cities (25 分)
题目:n个城市(1到n),m条路,k个询问的城市,问当某城被攻陷时,若使其它各城连通,至少要修几条路。
思路:vis[i]标识该城是否访问,若被攻陷则置为1,遍历1到n,若不为1则dfs——标记,访问与其联通的点,计算连通分量,最少需要修的道路的数量为连通分量-1
注意:cin、cout会超时
- 用scanf、printf
- ios::sync_with_stdio(false) (synchronize同步)
#include<iostream>
#include<cstring>
using namespace std;
int vis[1005],mp[1005][1005];
int n;
void dfs(int x) {
vis[x]=1;
for(int i=1; i<=n; i++)
if(vis[i]==0&&mp[x][i]==1)
dfs(i);
}
int main() {
ios::sync_with_stdio(false); //神奇的不超时办法!!!
int m,k,cnt;
cin>>n>>m>>k;
int a,b,x;
for(int i=0; i<m; i++) {
cin>>a>>b;
mp[a][b]=mp[b][a]=1;
}
for(int i=0; i<k; i++) {
memset(vis,0,sizeof vis);
cnt=0;
cin>>x;
vis[x]=1;
for(int i=1; i<=n; i++) {
if(vis[i]==0) {
dfs(i);
cnt++;
}
}
cout<<cnt-1<<endl;
}
return 0;
}
1021 Deepest Root (25 分)
题意:n个点,n-1条边,若为树,输出使树达到最大高度的根节点
思路:
- dfs 判断连通分量个数,不为1,直接输出
- 从任一节点遍历得到最大高度的节点们set1,从set1中任一节点开始,遍历得到最大高度的节点们set2,二者并集即为所求
步骤:
- 点多边少——邻接矩阵vector<int> v[maxn]
- 遍历-->未标记dfs-->第一次且得到节点不为空存进set,第一个节点保存为根节点
- cnt不唯一直接输出
- 否则从根节点遍历得到tmp存入set
- set自动从小到大排列,直接输出
#include<iostream>
#include<vector>
#include<set>
using namespace std;
int n,maxh=0;
int vis[10005];
vector<int> v[10005],tmp;
set<int> ans;
void dfs(int x,int h) {
vis[x]=1;
if(h>maxh) {
maxh=h;
tmp.clear();
tmp.push_back(x);
} else if(h==maxh)
tmp.push_back(x);
for(int i=0; i<v[x].size(); i++)
if(vis[v[x][i]]==0) //
dfs(v[x][i],h+1);
}
int main() {
ios::sync_with_stdio(false);
int a,b,cnt=0,root;
cin>>n;
for(int i=1; i<n; i++) {
cin>>a>>b;
v[a].push_back(b);
v[b].push_back(a);
}
for(int i=1; i<=n; i++) {
if(vis[i]==0) {
dfs(i,1);
cnt++;
if(i==1) {
if(tmp.size()) {
root=tmp[0];
for(int i=0; i<tmp.size(); i++)
ans.insert(tmp[i]);
}
}
}
}
if(cnt>1) printf("Error: %d components\n",cnt);
else {
fill(vis,vis+10005,0);
tmp.clear();
dfs(root,1);
for(int i=0; i<tmp.size(); i++)
ans.insert(tmp[i]);
//set<int>::iterator it=ans.begin();
for(auto it=ans.begin(); it!=ans.end(); it++) printf("%d\n",*it);
}
return 0;
}
1034 Head of a Gang (30 分)
题意:n条通话记录,标准时间k,找出团伙个数(总时间>k,人数>2)及每个团伙头目(打电话时间最长的那个)和成员个数
思路:dfs求连通分量+判断
步骤:
- n条记录最多2*n个人
- 两个map将name与num对应标记
- 个人times输入时就累加记录(日后用于选出头目)
- 遍历dfsMap-->未标记dfs,判断当前团伙是否符合条件
- dfs:cnt++标记,时刻更新头目,累加总时长,mp[x][i]置零(避免环),若未标记dfs,引用直接返回cnt和total用于比较
#include<iostream>
#include<vector>
#include<set>
#include<map>
using namespace std;
int n,k,pos=1;
int vis[2005],times[2005],mp[2005][2005];
map<string,int> num;
map<int,string> name;
map<string,int> ans;
int getId(string s){
if(num[s]==0){
num[s]=pos;
name[pos]=s;
return pos++;
}else return num[s];
}
void dfs(int x,int &head,int &cnt,int &total){
cnt++;
vis[x]=1;
if(times[x]>times[head]) head=x;
for(int i=1;i<=n;i++){
if(mp[x][i]!=0){
total+=mp[x][i];
mp[x][i]=mp[i][x]=0;
if(!vis[i]) dfs(i,head,cnt,total);
}
}
}
void dfsMap(){
for(int i=1;i<=n;i++){
if(!vis[i]){
int cnt=0,head=i,total=0;
dfs(i,head,cnt,total);
if(cnt>2&&total>k) ans[name[head]]=cnt;
}
}
}
int main() {
cin>>n>>k;
string s1,s2;
int a,b,t;
for(int i=1;i<=n;i++){
cin>>s1>>s2>>t;
a=getId(s1),b=getId(s2);
mp[a][b]+=t;
mp[b][a]+=t;
times[a]+=t;
times[b]+=t;
}
dfsMap();
cout<<ans.size()<<endl;
for(auto it=ans.begin();it!=ans.end();it++)
cout<<it->first<<' '<<it->second<<endl;
return 0;
}
1072 Gas Station (30 分)
题意:n个房子,m个加气站,k加气站最大覆盖范围。要求找出一加气站,使其覆盖所有房子,且距房子的最小距离最大,若多个解,输出平均值最小的那个,若还相同输出加气站下标最小的那个
思路:对m个加气站依次dijkstra,比较求最优解
步骤:
- 房子序号1到n,加气站序号n+1到n+m (1000+10)
- 从n+1到n+m依次dis[id]=0, Dijkstra(vis[i]!=0)
- 1到n:dis[i]>ds mind=-1 break 否则mind=inf(dis[i]中取最小),avg=0(累加dis[i])
- ansd=-1(mind中取最大),ansavg=inf(avg中取最小)
#include<iostream>
#include<string>
using namespace std;
const int inf=99999999;
int dis[1015],vis[1015],mp[1015][1015];
int n,m,k,ds;
int getId(string s) {
if(isdigit(s[0])) return stoi(s);
return n+stoi(s.substr(1));
}
int main() {
fill(mp[0],mp[0]+1015*1015,inf);
fill(dis,dis+1015,inf);
cin>>n>>m>>k>>ds;
string s1,s2;
int a,b,l;
for(int i=0; i<k; i++) {
cin>>s1>>s2>>l;
a=getId(s1);
b=getId(s2);
mp[a][b]=mp[b][a]=l;
}
int ansid=-1;
double ansd=-1,ansavg=inf;
for(int id=n+1; id<=n+m; id++) {
fill(dis,dis+1015,inf);
fill(vis,vis+1015,0);
double mind=inf,avg=0;
dis[id] = 0; //!!!
for(int i=1; i<=m+n; i++) { //dijkstra
int minn=inf,u=-1;
for(int j=1; j<=n+m; j++)
if(!vis[j]&&dis[j]<minn)// vis
minn=dis[j],u=j;
if(u==-1) break;
vis[u]=1;
for(int j=1; j<=n+m; j++) {
if(!vis[j]&&mp[u][j]!=inf) {
if(dis[j]>dis[u]+mp[u][j])
dis[j]=dis[u]+mp[u][j];
}
}
}
for(int i=1; i<=n; i++) {
if(dis[i]>ds) {
mind=-1;
break;
}
if(dis[i]<mind) mind=dis[i];
avg+=1.0*dis[i];
}
if(mind==-1) continue;
avg/=n;
if(mind>ansd) {
ansd=mind;
ansid=id;
ansavg=avg;
} else if(mind==ansd&&avg<ansavg) {
ansid=id;
ansavg=avg;
}
}
if(ansid==-1) cout<<"No Solution\n";
else printf("G%d\n%.1f %.1f\n",ansid-n,ansd,ansavg);
return 0;
}
1076 Forwards on Weibo (30 分)
题意:有n个用户(序号从1到n),最大层数为l,给出每个用户关注的人数及具体的ID,给出k个询问,问id在l层内(包括l)最多有多少个关注她的人。
注意:dfs有两个点过不去,bfs就过了(bfs注意pop())
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
int n,l;
int vis[1005];
vector<int> vc[1005];
struct node {
int id;
int lev;
} a[1005];
void bfs(int root) {
int cnt=0;
node t,r;
queue<node>q;
q.push(node {root,0});
while(!q.empty()) {
t=q.front();
q.pop();//!!!
for(int i=0; i<vc[t.id].size(); i++) {
int p=vc[t.id][i];
r=node {p,t.lev+1};
if(vis[p]==0&&r.lev<=l) {
vis[p]=1;
cnt++;
q.push(r);
//cout<<"level:"<<r.lev<<" point: "<<r.id<<endl;
}
if(r.lev>l) break;
}
}
cout<<cnt<<endl;
}
int main() {
ios::sync_with_stdio(false);
cin>>n>>l;
int k,x;
for(int i=1; i<=n; i++) {
cin>>k;
for(int j=1; j<=k; j++) {
cin>>x;
vc[x].push_back(i);
}
}
cin>>k;
for(int i=0; i<k; i++) {
cin>>x;
fill(vis,vis+1005,0);
vis[x]=1;
bfs(x);
//cout<<"this is "<<i+1<<endl;
}
return 0;
}