跟着制药一起来刷题

跟着制药一起来刷题,第1张

目录

1.打乱字母

 2.分考场

 3.合根植物


1.打乱字母

农夫约翰将按字典序排列的 N头奶牛的名字列表贴在了牛棚的门上。


每个奶牛的名字都由一个长度介于 1 到 20 之间的由小写字母构成的唯一字符串表示。


麻烦制造者贝茜将列表中的奶牛名字重新排序打乱了列表。


此外,她还对每头奶牛的名字中的字母顺序进行了重新排列(也可能保持不变)。


给定修改过后的列表,请帮助约翰确定列表中的每个名字可能出现在原始列表中的最低和最高位置。


 题解思路:二分+贪心,题目中要求最前的位置和最后的位置,要让当前字符串排最靠前,换言之是让其他所有的字符串排最靠后,反之,要让当前字符串排最靠后,换言之是让其他的字符串排最靠前,明白了之后我们就可以用二分实现,具体看代码。


#include 
#include 
#include 

using namespace std;

const int N = 50010;

int n;
string a[N], b[N], c[N];

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i ++ )
    {
        cin >> a[i];
        b[i] = c[i] = a[i];
        sort(b[i].begin(), b[i].end(), greater());//将每个字符串的字典序从大到小排序
        sort(c[i].begin(), c[i].end());//将每个字符串的字典序从小到大排序
    }
// 先把整个序列全部变成最大值,    当前数取最小值,其余数求最大值,
    sort(b + 1, b + n + 1);//从小到大排序所有字符串
    sort(c + 1, c + n + 1);

    for (int i = 1; i <= n; i ++ )
    {

 //最小的情况在最大的数组里面找(左边界),最大的情况在最小的里面找(右边界)
        sort(a[i].begin(), a[i].end());
        int l = 1, r = n;
        while (l < r)//在全部都是最大字典序的数组中找到第一个字典序大于等于a升序排序中的元素的位置
        {
            int mid = l + r >> 1;
            if (b[mid] >= a[i]) r = mid;
            else l = mid + 1;
        }

        cout << r << ' ';
        reverse(a[i].begin(), a[i].end());
        l = 1, r = n;
        while (l < r)//在全部都是最小字典序的数组中找到最后一个字典序小于等于a降序排序中的元素的位置
        {
            int mid = l + r + 1 >> 1;
            if (c[mid] <= a[i]) l = mid;
            else r = mid - 1;
        }

        cout << r << endl;
    }

    return 0;
}
 2.分考场

题目链接 分考场

 n个人参加某项特殊考试。



  为了公平,要求任何两个认识的人不能分在同一个考场。



  求是少需要分几个考场才能满足条件。


题解思路: 我们依次枚举各个考场,如果第i个考场满足条件,学生x就进入i考场;如果i考场不满足条件,我们继续判断i+1考场。


如此往复,当我们把kn个考场全部枚举完,发现学生x与每个考场都存在认识关系,那么我们必须为x新开辟一个考场了。


 该题参考博客: 历届试题 分考场_diefun的博客-CSDN博客_分考场

#include
using namespace std;
int g[110][110],p[110][110];//g数组用来维护考生间关系,p数组代表的是考场中的座位号				
int n,num=110;
void dfs(int x,int kn)//x考生数 kn考场数	
{ 
	if(kn>=num) return;//说明当前考场数已经枚举完了那么就返回			
  	if(x>n) 
  	{
  	    num=min(num,kn); 
  	    return;
  	    
  	}
  	    
		
	for(int j=1;j<=kn;j++)//枚举考场 
	{						
	   	int k=0;//k是从0一直变化的,其实代表的就是考场中的座位号
	   		/*找到一个空位 并且与该考场人无关系 */
		while(p[j][k] && !g[x][p[j][k]]) k++; //如果这个当前第j个考场第k个位置上有人且x和该考生不认识的话那么就k++,
		//就判断下一个位置
		
		if(p[j][k]==0)						
		//满足条件 说明当前考场x可以坐那么就判断下一个学生
		{
			p[j][k]=x;
			dfs(x+1,kn);
			p[j][k]=0;//恢复现场
		}
   	}                                  		 	  
	p[kn+1][0]=x;//遍历所有考场 发现都不行 只能新开辟一个考场					
	dfs(x+1,kn+1);							
	p[kn+1][0]=0;									
}
int main()
{
	int m,a,b;
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{ 
		cin>>a>>b;
		g[a][b]=g[b][a]=1; 	//代表他们之间认识		
	}
	dfs(1,1);
	cout<
 3.合根植物

题解思路:并查集

#include
using namespace std;
#define N 1000005
int pre[N];
int n,m,k;
int find(int x)   //边找边压缩路径
{
	if(x==pre[x])
		return x;
	return pre[x]=find(pre[x]);
}
void merge(int x,int y)//将两个点合并为同一个祖宗节点
{
	int fx=find(x);
	int fy=find(y);
	if(fx==fy)
		return;
	pre[fx]=fy;
}
void init()   //初始化
{
	for(int i=1;i<=n;i++)
		pre[i]=i;
}
int main()
{
	int ans=0,u,v;
	cin>>n>>m>>k;
	n=n*m;
	init();
	for(int i=0;i>u>>v;
		merge(u,v);//将输入的点进行连根
	}
	for(int i=1;i<=n;i++)
	{
		if(pre[i]==i)//祖宗节点没有改变则 ans++,改变了的说明都和别的点连成同一棵植物了
			ans++;
	}
	cout<

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/562655.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-02
下一篇 2022-04-02

发表评论

登录后才能评论

评论列表(0条)