首页 > 其他分享 >Test 2022.09.21

Test 2022.09.21

时间:2022-09-21 21:35:22浏览次数:76  
标签:21 tote int top dfn maxn low 2022.09 Test

今天是\(JSOI2010\)专场

T1满汉全席(2-SAT

比较生疏的知识点,当时看着一眼就觉得是图论,甚至想到了最大流,但是因为建不来图,被迫去打了暴力,然而只得到\(10pts\),事实证明我的想法是正确的,但是太菜了。

关于\(2-SAT\)

这类问题就是对于\(n\)个不同的命题,存在命题\(a,b\),若\(a\)不成立,那么\(b\)就必须成立(反之亦然)。

举个例子

有三对夫妻\(ai,bi\)要参加舞会,每对夫妻至少有一人参加,是否存在一种方案使得题意被满足。建立状态\(0,1\)表示参加和不参加,已知有一些夫妻之间存在矛盾,例如\(a1,b2\)不能同时存在,即\(a1\)参加(\(1\))\(b2\)就不能参加(\(0\)),就可以用建图和\(tarjan\)求强连通分量、或者是\(dfs\)来解决建图后的问题。
根据以上性质,在这个例子中我们可以从\(a1\)的\(1\)状态向\(b2\)的\(0\)状态连一条有向边,再从\(a1\)的\(0\)状态向\(b2\)的\(1\)状态连另一条有向边,这样我们就成功地描述了事情之间的因果逻辑。

解决问题

在建好图以后,怎么处理这样一条条的逻辑关系呢?我们可以使用\(tarjan\)求强联通分量的算法,为什么呢?因为这些逻辑关系实际上就是单向的“导致”,在一个强连通分量内,所有命题必须同时存在,如果有两个互斥的条件同时存在于一个\(SCC\)中,那么就是不能满足的。
同理在这个题里,如果一个评委的要求\(1\)不能被满足,那么要求\(2\)就是必须被满足的,所以我们建边的方式就有了,之后的\(tarjan\)照着打就行了,只是多组数据记得该重置的要重置(特别是head[maxn]数组!!)

点击查看代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e4+10;
int n,m;
struct Edge{int u,v;int nex;}E[maxn];
int tote=0;int head[maxn];
void add(int u,int v)
{
	E[++tote].u=u,E[tote].v=v;
	E[tote].nex=head[u];head[u]=tote;
}
int dfn[maxn],low[maxn],cnt=0,s[maxn]/*栈*/,ins[maxn],top;
int scc[maxn],num=0; // 结点 i 所在 SCC 的编号、当前的scc个数 
void tarjan(int x) 
{
	low[x]=dfn[x]=++cnt;
	s[++top]=x;ins[x]=1;
	for(int i=head[x];i;i=E[i].nex) 
	{
		int v=E[i].v;
		if(!dfn[v])
		{
			tarjan(v);
			low[x]=min(low[x], low[v]);
		}
		else if(ins[v]) 
			low[x]=min(low[x],dfn[v]);
	}
	if(dfn[x]==low[x])
	{
		++num;
		while(s[top]!=x)
		{
			scc[s[top]]=num;
			ins[s[top]]=0;
			top--;
		}
		scc[s[top]]=num;
		ins[s[top]]=0;
		--top;
	}
}
void reset()
{
	memset(head,0,sizeof head);
	memset(dfn,0,sizeof dfn);
	memset(low,0,sizeof low);
	memset(ins,0,sizeof ins);
	memset(s,0,sizeof s);
	top=tote=cnt=num=0; 
}
inline int read()
{
	int x=0,f=1;
	char c=getchar();
	while('0'>c||c>'9')
	{
		if(c=='-')f=-1;
		c=getchar(); 
	}
	while('0'<=c&&c<='9')
	{
		x=(x<<1)+(x<<3)+(c^48);
		c=getchar();
	}
	return x*f;
}
//1~n 'm'  n+1~2n 'h'
char tmp1[10],tmp2[10];
void trans(char a1[],char a2[])
{
	int c1=0,c2=0;
	for(int i=1;i<strlen(a1);i++)
		c1=c1*10+a1[i]-'0';
	for(int i=1;i<strlen(a2);i++)
		c2=c2*10+a2[i]-'0';
	add(a1[0]=='m'?c1+n:c1,a2[0]=='m'?c2:c2+n);
}
int main()
{
	int t=read();
	while(t--)
	{
		reset();
		n=read(),m=read();
		for(int i=1;i<=m;i++)
		{
			scanf("%s %s",tmp1,tmp2);
			trans(tmp1,tmp2),trans(tmp2,tmp1);
		}
		for(int i=1;i<=n*2;i++)if(!dfn[i])tarjan(i);
		int flag=0; 
		for(int i=1;i<=n;i++)
		{	
			if(scc[i]==scc[i+n])
			{
				flag=1;
				break;
			}
		}
		if(flag==1)puts("BAD");
		else puts("GOOD");
	} 
	return 0;
}
/*
2
3 4
m3 h1
m1 m2
h1 h3
h3 m2
2 4
h1 m2
m2 m1 
h1 h2
m1 h2 
*/

T2部落划分

一眼最小生成树(传统艺能了)

连一条有效边就让集合减少1个,初始n个,目标k个,所以只用连n-k个就行,连完了n-k个边后,下一个可以合并集合的边就是要求的答案了

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+100;
double calc(double x1,double y1,double x2,double y2){return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));}
int n,k;int x,y;
struct Edge{int u,v;double w;}E[maxn];int tote;
struct point{int x;int y;}p[maxn];
bool cmp(Edge a,Edge b){return a.w<b.w;}
int f[maxn];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
inline int read()
{
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9')
	{
		if(c=='-')f=-1;
		c=getchar();
	}
	while('0'<=c&&c<='9')
	{
		x=(x<<1)+(x<<3)+(c^48);
		c=getchar();
	}
	return x*f;
}
int main()
{
	freopen("group.in","r",stdin);
	freopen("group.out","w",stdout);
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)p[i].x=read(),p[i].y=read(),f[i]=i;
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++) 
			E[++tote].u=i,E[tote].v=j,E[tote].w=calc(p[i].x,p[i].y,p[j].x,p[j].y);
	sort(E+1,E+tote+1,cmp);
	int cnt=0;int flag=0;
	for(int i=1;i<=tote;i++)
	{
		if(cnt==n-k)
		{
			flag=1; 
		}
		int x=find(E[i].u),y=find(E[i].v);
		if(x!=y)
		{
			cnt++;
			if(flag==1)
			{
				printf("%.2lf",E[i].w);
				break;
			}
			f[x]=y;
		}
	}
	return 0;
}
/*
4 2
0 0
0 1
1 1
1 0
1.00
*/
/*
9 3
2 2
2 3
3 2
3 3
3 5
3 6
4 6
6 2
6 3
2.00
*/

T3冷冻波

明天再来打

T4蔬菜庆典

明天再来打

标签:21,tote,int,top,dfn,maxn,low,2022.09,Test
From: https://www.cnblogs.com/Hanggoash/p/16717192.html

相关文章

  • 9-21next
    新建表格  用来进行本地信息交互   需要在uec++中继承FTableRowBase格式如下“”:  FInputChord是设置按键的结构体......
  • 9.21-CSP-S模拟8
    T1JOI2022FinalT3「選挙で勝とう/Let'sWintheElection」赛时对着一个假贪心不知道为什么是错的。贪心就是枚举选几个协作州,然后贪心把小的都拿了,剩下的支持州......
  • 【C++】GoogleTest入门指南
    参考:GoogleTest官网基本概念要使用GoogleTest,需要包含headergtest/gtest.h断言Assertions断言是检查条件是否为真的语句,其结果可能是成功或失败,失败分为非致命失败和......
  • 运行 docker run hello-world 报错 Unable to find image ‘hello-world:latest‘ loc
    原文链接:https://blog.csdn.net/weixin_43520450/article/details/107377342报错提示如下:解决办法:1、执行以下命令vi/etc/docker/daemon.json2、添加以下的内容并保......
  • 0921v-for
    <html> <head> <metacharset="utf-8"/> <title></title> <scriptsrc="js/vue.js"type="text/javascript"charset="utf-8"></script> </head><body> <divi......
  • 0921v-show
    <html> <head> <metacharset="utf-8"/> <title></title> <scriptsrc="js/vue.js"type="text/javascript"charset="utf-8"></script> </head><body> <divi......
  • 20220921 模拟赛
    T1彩票\(n\leq10^5\)。发现三等奖有三种情况,一等奖和二等奖却都只有一种情况,感觉很烦,考虑暴力做掉三等奖的彩票号码,直接三重循环枚举,这一部分消耗\(O(\dfrac{100^3......
  • CSP 2021
    普及分糖果(红)没有1A,身败名裂)点击查看代码#include<bits/stdc++.h>#definefffflush(stdout)#definethankputs("感恩......
  • 9.21Leetcode记录
    一、数据流中的中位数题目如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那......
  • lc-0921
    lc206反转链表classSolution{publicListNodereverseList(ListNodehead){ListNodeprev=null;ListNodecurr=head;while(cu......