patA1034
首先DISS一下devc,个byd玩意一调试就闪退,感谢你帮鼠鼠治疗低血压,还是VS2019好用啊。
巨坑:N为通话数,按照极端情况,最多会有2N个人,所以要把数组开到2N个元素,否则会挂一个测试样例(段错误)。读题一定要认真。
分析题目,不难看出要用到DFS来找连通分量,然后计算每个连通分量的边权之和。计算边权之和有两种方法:(1)在DFS的过程中,对每个节点,先将与之相连的边的权值加上,然后再判断相邻节点是否已被访问过;每访问完一条边,就将其权值设为0。 (2)在edge结构体中增加一个属性,标记该边是否被访问过。
为了将字符串进行排序,可以使用stl的sort方法,也可以将数据存入std::map容器中,这样使用迭代器遍历的时候会自动将其按照增序排序。
实现方法1:
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <set>
using namespace std;
/*储存一条边*/
struct edge{
int v; //节点编号,从0开始
int w; //边权
edge(int x,int y):v(x),w(y){}
};
#define MAX 2000
//人数
int N=0;
//阈值
int K=0;
//邻接表
vector<edge> adj[MAX];
//姓名-编号map
map<string,int> map1;
//编号-姓名map
map<int,string> map2;
//点权数组
int vw[MAX]={0};
//input中记录已经有多少节点
int mycount=0;
//当前已知连通分量数
int compnum=0;
//leader-节点数map
map<string,int> map3;
//找到的所有满足条件的连通分量
vector<int> comp[MAX];
//标记节点是否被访问过
bool visit[MAX]={false};
using namespace std;
/*判断名字是否在map中,并返回编号。若名字不在map中,将名字加入map1和map2*/
int inmap(string name){
map<string,int>::iterator iter=map1.find(name);
if(iter==map1.end()){
map1.insert(pair<string,int>(name,mycount));
map2.insert(pair<int,string>(mycount,name));
return mycount++;
}
else{
return (*iter).second;
}
}
/*读取输入*/
void input(){
cin>>N>>K;
string name1,name2;
int w;
for(int i=0;i<N;i++){
cin>>name1>>name2>>w;
int v1=inmap(name1);
int v2=inmap(name2);
/*将新边加入邻接表*/
bool flag=true;
for(int i=0;i<adj[v1].size();i++){
if(adj[v1][i].v==v2){
adj[v1][i].w+=w;
flag=false;
break;
}
}
if(flag)
adj[v1].push_back(edge(v2,w));
flag=true;
for(int i=0;i<adj[v2].size();i++){
if(adj[v2][i].v==v1){
adj[v2][i].w+=w;
flag=false;
break;
}
}
if(flag)
adj[v2].push_back(edge(v1,w));
/*计算点权*/
vw[v1]+=w;
vw[v2]+=w;
}
}
/*利用DFS获取满足条件的联通分量成员,计算边权和*/
int DFS(int u){
visit[u]=true;
comp[compnum].push_back(u);
//当前总边权
int totalweight=0;
for(int i=0;i<adj[u].size();i++){
int v=adj[u][i].v;
totalweight+=adj[u][i].w;
//将边权设为0
adj[u][i].w=0;
for(int j=0;j<adj[v].size();j++){
if(adj[v][j].v==u){
adj[v][j].w=0;
break;
}
}
//将未被访问过的节点加入连通分量
if(!visit[v]){
//继续DFS
totalweight+=DFS(v);
}
}
return totalweight;
}
/*对图DFS,找到所有满足条件的连通分量,将其加入comp*/
void find(){
for(int i=0;i<N;i++){
if(!visit[i]){
int totalweight=DFS(i);
if(totalweight<=K || comp[compnum].size()<=2){
//删掉新加入的分量
comp[compnum].clear();
continue;
}
compnum++;
}
}
}
/*完成map3*/
void getleader(){
//遍历comp集合,获取每个连通分量的leader
for(int j=0;j<compnum;j++) {
vector<int> vec=comp[j];
//当前点权的最大值
int temp=0;
//leader的编号
int leader;
for(int i=0;i<vec.size();i++){
int u = vec[i];
if(vw[u]>temp){
temp=vw[u];
leader=u;
}
}
//将leader的信息加入map3
string leadername=map2.find(leader)->second;
map3.insert(pair<string,int>(leadername,vec.size()));
}
}
int main(void){
input();
find();
getleader();
//遍历map3,输出数据]
cout<<map3.size()<<endl;
for(map<string,int>::iterator iter=map3.begin();iter!=map3.end();iter++) {
cout<<iter->first<<" "<<iter->second<<endl;
}
return 0;
}
实现方法2:
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <set>
using namespace std;
/*储存一条边*/
struct edge{
int v; //节点编号,从0开始
int w; //边权
bool isvisit; //标记该边是否被visit过
edge(int x,int y):v(x),w(y),isvisit(false){}
};
#define MAX 2000
//人数
int N=0;
//阈值
int K=0;
//邻接表
vector<edge> adj[MAX];
//姓名-编号map
map<string,int> map1;
//编号-姓名map
map<int,string> map2;
//点权数组
int vw[MAX]={0};
//input中记录已经有多少节点
int mycount=0;
//当前已知连通分量数
int compnum=0;
//leader-节点数map
map<string,int> map3;
//找到的所有满足条件的连通分量
vector<int> comp[MAX];
//标记节点是否被访问过
bool visit[MAX]={false};
using namespace std;
/*判断名字是否在map中,并返回编号。若名字不在map中,将名字加入map1和map2*/
int inmap(string name){
map<string,int>::iterator iter=map1.find(name);
if(iter==map1.end()){
map1.insert(pair<string,int>(name,mycount));
map2.insert(pair<int,string>(mycount,name));
return mycount++;
}
else{
return (*iter).second;
}
}
/*读取输入*/
void input(){
cin>>N>>K;
string name1,name2;
int w;
for(int i=0;i<N;i++){
cin>>name1>>name2>>w;
int v1=inmap(name1);
int v2=inmap(name2);
/*将新边加入邻接表*/
bool flag=true;
for(int i=0;i<adj[v1].size();i++){
if(adj[v1][i].v==v2){
adj[v1][i].w+=w;
flag=false;
break;
}
}
if(flag)
adj[v1].push_back(edge(v2,w));
flag=true;
for(int i=0;i<adj[v2].size();i++){
if(adj[v2][i].v==v1){
adj[v2][i].w+=w;
flag=false;
break;
}
}
if(flag)
adj[v2].push_back(edge(v1,w));
/*计算点权*/
vw[v1]+=w;
vw[v2]+=w;
}
}
/*利用DFS获取满足条件的联通分量成员,计算边权和*/
int DFS(int u){
visit[u]=true;
comp[compnum].push_back(u);
//当前总边权
int totalweight=0;
for(int i=0;i<adj[u].size();i++){
int v=adj[u][i].v;
if (!adj[u][i].isvisit) {
totalweight += adj[u][i].w;
/*修改边的访问状态*/
adj[u][i].isvisit = true;
for (int j = 0; j < adj[v].size(); j++) {
if (adj[v][j].v == u) {
adj[v][j].isvisit = true;
}
}
}
//将未被访问过的节点加入连通分量
if(!visit[v]){
//继续DFS
totalweight+=DFS(v);
}
}
return totalweight;
}
/*对图DFS,找到所有满足条件的连通分量,将其加入comp*/
void find(){
for(int i=0;i<N;i++){
if(!visit[i]){
int totalweight=DFS(i);
if(totalweight<=K || comp[compnum].size()<=2){
//删掉新加入的分量
comp[compnum].clear();
continue;
}
compnum++;
}
}
}
/*完成map3*/
void getleader(){
//遍历comp集合,获取每个连通分量的leader
for(int j=0;j<compnum;j++) {
vector<int> vec=comp[j];
//当前点权的最大值
int temp=0;
//leader的编号
int leader;
for(int i=0;i<vec.size();i++){
int u = vec[i];
if(vw[u]>temp){
temp=vw[u];
leader=u;
}
}
//将leader的信息加入map3
string leadername=map2.find(leader)->second;
map3.insert(pair<string,int>(leadername,vec.size()));
}
}
int main(void){
input();
find();
getleader();
//遍历map3,输出数据
cout<<map3.size()<<endl;
for(map<string,int>::iterator iter=map3.begin();iter!=map3.end();iter++) {
cout<<iter->first<<" "<<iter->second<<endl;
}
return 0;
}
~~

浙公网安备 33010602011771号