算法训练 infiltration

本文介绍了一种解决复杂组织渗透问题的算法,通过广度优先搜索(BFS)找到控制所有单位所需的最小单位数量及具体方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述
  早上好,特工W-12,你需要完成的以下的任务。
  我们已经渗透到一个叫混乱与祸害的组织中,希望能掌握该组织的管理权。不幸的是,它们似乎已经准备好应对这样的事件了,它们使用了一个很复杂的设计分配管理权力,这使得我们的渗透工作非常艰难。
  那家组织的管理系统被分成若干个单位,对于任意两个单位A和B,要么A管理B要么B管理A,同时这个管理关系可以形成环,因此可以出现A管理B、B管理C、C管理A的情况。
  我们可以安排特工去渗透到任意一个单位,那将使得我们控制该单位和那个单位直接管理的单位,但是不包括间接管理的单位。比如之前的样例,渗透到A单位会让我们控制A和B,但不能控制C。
  对于一个成功的渗透工作来说,我们必须要控制所有的单位才行,否则其他单位会发现我们,同时破坏我们的计划。而你也知道,我们现在从更高的部门那里拿到的经费十分紧缺,我们必须最高效地完成任务。你的任务就是要找出控制单位最少的可行方案。
输入格式
  第一行包含一个整数n,表示该组织的单位数。接下来n行每行n个二进制位。在其中的第i行第j列位置,若为1表示i单位控制j单位,否则j单位控制i单位。
输出格式
  共一行,第一个整数ans表示最少的控制单位数量,接下来ans个整数表示任意一组可行的方案。
样例输入
样例1:
2
00
10
样例2:
3
010
001
100
样例3:
5
01000
00011
11001
10100
10010
样例输出
样例1:
1 2
样例2:
2 1 2
样例3:
2 2 3
数据规模和约定
  30%的数据n<=10。
  50%的数据n<=30。
  100%的数据n<=75。

  保证n*n的01矩阵中所有的i行i列位置为0,i行j列和j行i列两个位置恰好一个为1一个为0(i≠j)。

这道题隐含了一个条件,对角线上的0其实可以看为1,最后题目就演变成了找出最少的字符串数,使字符串的值全变为1。

开始本来想用暴力法枚举,看了下数据量与算法量觉得肯定会超时,就用了广搜进行判断。

不过20组数据还是有2组超时了...只有90分。

import java.util.HashSet;
import java.util.LinkedList;
import java.util.Scanner;

public class infiltration {
	static String []m;
	static String end="";
	static int n;
	static class edge
	{
		String now;//存储字符串
		int count; //存储步数
		int a[];   //存储已经加了的编号
		public edge(String now,int count) 
		{
			this.now=now;
			this.count=count;
			a=new int[76];
		}
		public void input(int i)//加入一个新的编号
		{
			count++;
			a[count-1]=i;
		}
	}
	public static void bfs()
	{
		LinkedList<edge> a =new LinkedList<>();//用list模仿队列
		HashSet<String> hashSet=new HashSet<>();//防止重复的字符串
		for(int i=1;i<m.length;i++)
		{
			hashSet.add(m[i]);
			edge e=new edge(m[i], 0);
			e.input(i);
			a.add(e);
			if(m[i].equals(end))
			{
				System.out.print(1+" "+i);
				return;
			}
		}
		boolean flag=true;
		while(!a.isEmpty()&&flag)//进行bsf广搜
		{
			edge p=a.get(0);
			a.remove(0);
			for(int i=p.a[p.count-1]+1;i<=n;i++)
			{
				String b=Add(p.now, m[i]);
				if(!hashSet.contains(b))
				{
					edge k=new edge(p.now, p.count);
					for(int w=0;w<p.count;w++)
					{
						k.a[w]=p.a[w];
					}
					k.now=b;
					k.input(i);
					hashSet.add(b);
					a.add(k);
					if(b.equals(end))
					{
						flag=false;
						break;
					}
				}
				b=p.now;
			}		
		}
		edge ed=a.get(a.size()-1);
		System.out.print(ed.count+" ");
		for(int i=0;i<ed.count;i++)
		{
			System.out.print(ed.a[i]+" ");
		}
	}
	public static String Add(String a,String b)
	{
		char[] A=a.toCharArray();
		char[] B=b.toCharArray();
		String C="";
	
		for(int i=0;i<a.length();i++)
		{
			if(A[i]=='1'||B[i]=='1')
				A[i]='1';
			C=C+A[i];
		}
		return C;
	}
	public static void main(String args[])
	{
		Scanner sc=new Scanner(System.in);	
	        n=sc.nextInt();
		m=new String[n+1];
		
		for(int i=1;i<=n;i++)
		{
			end=end+'1';
			m[i]=sc.next();
			char[]M=m[i].toCharArray();//处理字符串
			m[i]="";
			M[i-1]='1';
			for(int j=0;j<n;j++)
			{
				m[i]=m[i]+M[j];
			}
		}
		bfs();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值