C - 班长竞选(Week 8作业)

题目

大学班级选班长,N 个同学均可以发表意见
若意见为 A B 则表示 A 认为 B 合适,意见具有传递性,即 A 认为 B 合适,B 认为 C 合适,则 A 也认为 C 合适
勤劳的 TT 收集了M条意见,想要知道最高票数,并给出一份候选人名单,即所有得票最多的同学,你能帮帮他吗?
Input:本题有多组数据。第一行 T 表示数据组数。每组数据开始有两个整数 N 和 M (2 <= n <= 5000, 0 <m <= 30000),接下来有 M 行包含两个整数 A 和 B(A != B) 表示 A 认为 B 合适。
Output:对于每组数据,第一行输出 “Case x: ”,x 表示数据的编号,从1开始,紧跟着是最高的票数。
接下来一行输出得票最多的同学的编号,用空格隔开,不忽略行末空格!

Sample Input

2
4 3
3 2
2 0
2 1

3 3
1 0
2 1
0 2

Sample Output

Case 1: 2
0 1
Case 2: 2
0 1 2

题目思路

思想:强连通分量 缩点
实现:通过强连通分量实现缩点,同一个强连通分量中的所有学生内部投票数相等(=n-1)
一个学生的得票数=内部得票数+其他与之相连的强连通分量的票数
对于内部得票数:
	等于内部人数-1
对于外部得票数:
	等于其他指向这个学生所在的连通分量的连通分量的人数

过程:
	构建原图和反向图
		fedge和dedge
	计算出每个节点对应的连通分量
		利用dfs计算出图的后序序列
		根据逆后序序列遍历反向图,构建强连通分量
		根据构建出的强连通分量进行缩点得到缩点后的图ledge,并记录下缩点后对应的内部节点个数
		遍历每一个节点,通过dfs利用连通分量计算得到的投票数
		找出最大投票数ansmax,并找出所有与ansmax相等的节点,输出

总结:这个题需要用到的数组和数比较多,在写的时候要注意思路清晰;同时,由于是多组数据,一定要确保数组和数初始化正确(提交发生了re原因就是有个数值没有进行初始化)

AC代码

#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=5005;
const int maxm=30010;
struct node{
	int to,nex;
}fedge[maxm],dedge[maxm],ledge[maxm];
int fhead[maxn],dhead[maxn],lhead[maxn],ans[maxn];
int vis[maxn],score[maxn],scc[maxn],lvis[maxn],dfn[maxn];
int m,n,N,t,fnum,dnum,lnum,dcnt,scnt,ansmax;
void add(int x,int y,node *edge,int *head,int &num)
{
	num++;
	edge[num].to=y;
	edge[num].nex=head[x];
	head[x]=num;
}
void lastedge()
{
	map<pair<int,int>,int> record;
	int ink[maxn];
	memset(ink,0,sizeof(ink));

	for(int x=0;x<n;x++)
		for(int i=fhead[x];i!=-1;i=fedge[i].nex){
			int y=fedge[i].to;
			int a=scc[x];int b=scc[y];
			if(record.find(make_pair(a,b))!=record.end()) continue;
			if(scc[y]!=scc[x]){
				add(scc[y],scc[x],ledge,lhead,lnum);
				record[make_pair(scc[y],scc[x])]=1;
			} 
	}	
}
void dfs1(int s)
{
	vis[s]=1;
	for(int i=fhead[s];i!=-1;i=fedge[i].nex)
		if(!vis[fedge[i].to]) dfs1(fedge[i].to);
	dfn[++dcnt]=s;
}
void dfs2(int s)
{
	scc[s]=scnt;
	score[scnt]++;
	for(int i=dhead[s];i!=-1;i=dedge[i].nex)
		if(!scc[dedge[i].to]) dfs2(dedge[i].to);
}
void kosaraju()
{
	dcnt=scnt=0;
	memset(scc,0,sizeof(scc));
	memset(vis,0,sizeof(vis));
	memset(score,0,sizeof(score));
	memset(dfn,0,sizeof(dfn));
	for(int i=0;i<n;i++)
		if(!vis[i]) dfs1(i);
	for(int i=n;i>=1;i--)
		if(!scc[dfn[i]]) ++scnt,dfs2(dfn[i]);
}
void dfs3(int s,int u)
{
	lvis[u]=1;
	for(int j=lhead[u];j!=-1;j=ledge[j].nex){
		int y=ledge[j].to;
		if(!lvis[y])
		{
			ans[s]+=score[y];
			lvis[y]=1;
			dfs3(s,y);
		}
	}			
}
void init()
{
	memset(fhead,-1,sizeof(fhead));
	memset(lhead,-1,sizeof(lhead));
	memset(dhead,-1,sizeof(dhead));
	memset(ans,0,sizeof(ans));
	fnum=0;dnum=0;lnum=0;
	ansmax=0;
}
int main()
{
	cin>>N;t=1;
	while(N--)
	{
		init();
		cin>>n>>m;
		for(int i=0;i<m;i++)
		{
			int u,v;
			cin>>u>>v;
			add(u,v,fedge,fhead,fnum);//原图 
			add(v,u,dedge,dhead,dnum);//反向图 
		}
		kosaraju();
		lastedge();
		for(int i=1;i<=scnt;i++)
		{
			memset(lvis,0,sizeof(lvis));			
			ans[i]+=score[i]-1;
			dfs3(i,i);
		}
		for(int i=1;i<=scnt;i++)
			ansmax=max(ansmax,ans[i]);
		
		cout<<"Case "<<t++<<": "<<ansmax<<endl;
		bool flag=true;
		for(int i=0;i<n;i++)
		{
			if(ans[scc[i]]==ansmax){
				if(flag) flag=false,cout<<i;
				else cout<<" "<<i;
			}
		}
		cout<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
优秀班委选举系统 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace 优秀班委选举 { public partial class Form1 : Form { private ListBox listBox; public Form1() { InitializeComponent(); } public Form1(ListBox listBox) { InitializeComponent(); this.listBox = listBox; } private void button1_Click(object sender, EventArgs e) { if (listBox1.Items.Count > 0) { if (listBox1.SelectedItem == null) { MessageBox.Show("请先选择一个对象!"); } else { //获取左边listBox1中选中的内容 string cont = listBox1.SelectedItem.ToString(); //左边listBox1中删除选中的内容 listBox1.Items.Remove(cont); //把获得的内容加入到右边的listBox2中 listBox2.Items.Add(cont); } } } private void button2_Click(object sender, EventArgs e) { if (listBox2.Items.Count > 0) { if (listBox2.SelectedItem == null) { MessageBox.Show("请先选择一个对象!"); } else { //获取右边listBox2中选中的内容 string cont = listBox2.SelectedItem.ToString(); //右边listBox2中删除选中的内容 listBox2.Items.Remove(cont); //把获得的内容加入到左边的listBox1中 listBox1.Items.Add(cont); } } } //退出 private void button5_Click(object sender, EventArgs e) { Application.Exit(); } //显示结果 private void button4_Click(object sender, EventArgs e) { //传递listBox2到Form2窗口中 Form2 form2 = new Form2(listBox2); form2.Show(); } //修改名单 private void button3_Click(object sender, EventArgs e) { if (listBox2.SelectedItem == null) { MessageBox.Show("请先选择一个对象!"); } else { string cont = listBox2.SelectedItem.ToString(); int index = listBox2.SelectedIndex; Form3 form3 = new Form3(cont, index, listBox2); form3.Show(); this.Hide(); } } //加载窗口 private void Form1_Load(object sender, EventArgs e) { if (listBox != null) { foreach (string str in listBox.Items) { listBox2.Items.Add(str); } } } } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值