2019.08.22 日常总结

洛谷P1407

题意:

我国的离婚率连续7年上升,今年的头两季,平均每天有近5000对夫妇离婚,大城市的离婚率上升最快,有研究婚姻问题的专家认为,是与简化离婚手续有关。

25岁的姗姗和男友谈恋爱半年就结婚,结婚不到两个月就离婚,是典型的“闪婚闪离”例子,而离婚的导火线是两个人争玩电脑游戏,丈夫一气之下,把电脑炸烂。

有社会工作者就表示,80后求助个案越来越多,有些是与父母过多干预有关。而根据民政部的统计,中国离婚五大城市首位是北京,其次是上海、深圳,广州和厦门,那么到底是什么原因导致我国成为离婚大国呢?有专家分析说,中国经济急速发展,加上女性越来越来越独立,另外,近年来简化离婚手续是其中一大原因。

——以上内容摘自第一视频门户

现代生活给人们施加的压力越来越大,离婚率的不断升高已成为现代社会的一大问题。而其中有许许多多的个案是由婚姻中的“不安定因素”引起的。妻子与丈夫吵架后,心如绞痛,于是寻求前男友的安慰,进而夫妻矛盾激化,最终以离婚收场,类似上述的案例数不胜数。

我们已知n对夫妻的婚姻状况,称第i对夫妻的男方为Bi,女方为Gi。若某男Bi与某女Gj曾经交往过(无论是大学,高中,亦或是幼儿园阶段,i≠j),则当某方与其配偶(即Bi与Gi或Bj与Gj)感情出现问题时,他们有私奔的可能性。不妨设Bi和其配偶Gi感情不和,于是Bi和Gj旧情复燃,进而Bj因被戴绿帽而感到不爽,联系上了他的初恋情人Gk……一串串的离婚事件像多米诺骨牌一般接踵而至。若在Bi和Gi离婚的前提下,这2n个人最终依然能够结合成n对情侣,那么我们称婚姻i为不安全的,否则婚姻i就是安全的。

给定所需信息,你的任务是判断每对婚姻是否安全。

思路:我们做个约定,夫妻从妻子向丈夫连一条边,初恋则从男方连一条边到女方。连边结束后,我们构建出来了一张图,对图进行Tarjan缩点,若某夫妻所在的强联通分量不一样则输出Safe,一样则输出Unsafe

代码:

#include 
using namespace std;
const int N=25000;
const int M=8100;
struct node{
	int next,to;
}e[N];int h[M],tot;
inline void add_edge_in_e(int a,int b){
	e[++tot]=(node){h[a],b};h[a]=tot;
}
//建图,注意是有向图
int dfn[N],low[N],dfscnt;
int Stack[N],stack_top;
int belong[N],dfscol;
void tarjan(int u){
	low[u]=dfn[u]=++dfscnt;
    //给每个节点一个dfs序
	Stack[++stack_top]=u;
	for(int i=h[u];i;i=e[i].next){
		register int v=e[i].to;
		if (!dfn[v]){
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if (!belong[v])
		low[u]=min(low[u],dfn[v]);
	}
    //别把u和v写反了啊!
	if (low[u]==dfn[u]){
		belong[u]=++dfscol;
		while (Stack[stack_top]!=u){
			int v=Stack[stack_top];
			belong[v]=dfscol;--stack_top;
		}
		--stack_top;//注意这一句哦!
	}
}
//Tarjan缩点的模板,最好理解,不行就背!
map a;
string boy,gril;
int n,m,i;
int main(){
	cin>>n;
	for(i=1;i<=n;i++){
		cin>>gril>>boy;
		a[gril]=i;a[boy]=i+n;
        //利用map对字符串进行编号(c++ STL 真好!)
		add_edge_in_e(i,i+n);
	}
	cin>>m;
	for(i=1;i<=m;i++){
		cin>>gril>>boy;
		add_edge_in_e(a[boy],a[gril]);
        //别连反了啊
	}
	for(i=1;i<=n*2;i++)
	if (!dfn[i]) tarjan(i);
	for(i=1;i<=n;i++){
		if (belong[i]!=belong[i+n])
		printf("Safe\n");
		else printf("Unsafe\n");
	}
	return 0;
}

洛谷P2704:

题意:

司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:

2019.08.22 日常总结_第1张图片

如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。 现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队?

思路:看到m这么小(m \leq 10!),所以肯定是状压dp。首先计算出每行所有的可能情况(就是m取到最大值,这一行的所有格子都是平地,状态数也才不到70个!设f[i][j][k]表示处理第i行,第i行状态为j,第i-1行状态为k,转移如代码(太长了,不想写!)

代码:

#include 
using namespace std;
const int N=80;
struct node{
	int val[N],a[N],num;
}st[110];
int f[110][N][N],t,n,m;
inline void get_state(int v,int t){
	for(int i=0;i<(1<>1)||i&(i>>2)) continue;
		//啊,要自己人打自己人了,赶紧删除状态
		register int x=0,j;
		for(j=1;j<=m;j++)
		if (i&(1<>n>>m;ans=-100;
	for(i=1;i<=n;i++){
		t=0;
		for(j=1;j<=m;j++){
			cin>>ch;
			if (ch=='P') t*=2;
			else t=t*2+1;
		}
		get_state(i,t);
	}
	for(j=1;j<=st[1].num;j++)
	f[1][j][0]=st[1].val[j];
	for(i=1;i<=st[1].num;i++)
	for(k=1;k<=st[2].num;k++)
	if (pd(1,i,2,k))
	f[2][k][i]=st[1].val[i]+st[2].val[k];
	//边界
	for(i=3;i<=n;i++)
	for(j=1;j<=st[i].num;j++)
	for(k=1;k<=st[i-1].num;k++)
	for(l=1;l<=st[i-2].num;l++)
	if (pd(i,j,i-1,k)&&pd(i,j,i-2,l)&&pd(i-1,k,i-2,l))
	f[i][j][k]=max(f[i][j][k],f[i-1][k][l]+st[i].val[j]);
	//转移
	for(i=1;i<=st[n-1].num;i++)
	for(l=1;l<=st[n].num;l++)
	if (pd(n-1,i,n,l))
	ans=max(ans,f[n][l][i]);
	//求解
	if (n==1){
		for(l=1;l<=st[1].num;l++)
		ans=max(ans,f[n][l][0]);
	}
	//特判
	cout<

 

你可能感兴趣的:(原创)