刷oj碰到的问题1(-180913)

1.poj 1039

在最后一步输出的时候,我一开始选用的是:printf("%.2lf\n",res);结果是wrong answer.

然后我改为cout<<setprecision(2)<<res<<endl;结果是wrong answer;改为cout<<fixed<<setprecision(2)<<res<<endl;结果正确.

然后我改为printf("%.2f\n");结果正确.

我认为这是由于编译器的问题造成的。上述实验选用的均为G++编译器。(查资料发现,果然是由于编译器的问题造成的结果错误,我使用vs写的c++代码,最好用c++编译;g++是GNU版本的,而c++则是VC++,微软出品的编译器!)

另:当使用cstdio+scanf/printf来做输入输出时,结果为:

而使用iostream+iomanip+cin/cout时,结果为:

当使用了:ios_base::sync_with_stdio(false);cin.tie(0);之后,结果为:

所以我们在做读入读出时,最好还是用scanf/printf。

最终结果为:

2.poj1845

在接收输入的时候,我采用了while(scanf_s() !=EOF)和while(scanf_s())两种写法,前者报错wrong answer,后者是output limit exceeded.

这里我也没明白错在哪了,因为实际上代码的问题不在于输入输出,而在于快速幂取模算法的括号!

3.poj1061

在输出的时候错了。取模的技巧:a%b = (a+b)%b,以此保证输出为正。

还有对应的数据应该同时交换。

4.poj1287

最小生成树

(1).prim算法:这里的第一层循环我一开始写了一个if(in_set[i]) continue;我的初衷是加快运算,但是其实这里的循环是用来控制我们最小生成树的边数的,所以我不能这么简单地加快运算。

5.poj2253

Floyd算法的应用:三层循环中i,j,k的位置,是k在最外层,i,j在内层。这是与我们常见的i,j,k顺序排列不同的。

6.poj1686

输出的yes和no都是全字母大写的!!!

注意接收输入的时候,连续的cin需要吞掉一个'\n',所以这时可以用cin.ignore()。

7.在自己电脑上的visual studio编程时,发现scanf,gets等函数已经被c++11给删除了(貌似是由于原函数存在漏洞),取而代之的是scanf_s,fgets。

scanf_s() != EOF是用在while循环中的常用技巧。fgets(char*,len,stdin)则能将一整行的内容全部读入,知道遇到换行符为止。

8.poj3356编辑距离

如何表示替换呢?

 

dp[i][j] = min(......,dp[i-1][j-1]+(A[i] != B[j]))

dp数组怎么初始化呢?

 

只用初始化[...][0]和[0][...],而他们的取值则与当前选取的坐标i,j有关。

做动态规划的时候,需要考虑i,j表示的元素是怎样迭代的,从而确保当前元素一定是经过已确定值的dp数组元素迭代得到的。

同时,也要注意比较的是i还是i-1。

9.leetcode 106由前序和后序构造二叉树

首先是vector的复制:v_new.assign(v_old.start(),v_old.end())

然后是复制的范围,需要注意两者是不同的。

第三是malloc前一个括号是指针类型,后一个括号是类的大小!

10.poj 3450字符串KMP算法

读取字符串的方法(用c语言):

char* data[200];
scanf_s("%s",data);
int data_len = strlen(data);

读取数字,遇零跳出循环的方式:

int num;
while(scanf("%d",&num) && num)
{...}

//or

int n;
while(scanf_s("%d",&n),n)
{...}

在vs2017下,strcpy之流均要加上_s的小尾巴。

在用string类做字符串搜索时,使用string.find(target_string,sta_pos) != string::npos,在用char*类做字符串搜索时,用strstr(source,target) != NULL

11.hdu 2433 求删掉一条边的最短路(可用BFS)

对一部分内存赋一样的值,如果是数组,可以使用memset(指针,赋的值,sizeof(指针));

memset主要用于为新申请的内存进行初始化,它是对较大的结构体和数组进行清零操作的一种最快方法.

在if,while等有判断条件的语句中,需要尤其注意的是哪个条件最重要(最容易否决结果),就应当先算哪个,比如同样的一道题,在两个判断条件互换位置前后的运算速度为:

这道题的一个tricky的地方在于,需要先记录每条最短路经过的边,这样可以大幅加快计算。其次是当每条边的长度为1的时候,可以将dijkstra简化为BFS。

 

12.hdu 4255

关于BFS中的,用来记录已访问元素的数组,它的值应该在何处修改:

我原先的习惯是,先将元素pop到容器外(比如堆或者队列或者栈或者集合),然后改变那个sign,也就是说,只有当他被遍历到的时候再修改sign;而在这道题中,这种方法就行不通了。我不知道为什么理论上行得通的方法,在测试的时候总是出问题,我通过输出sign来检查的时候,发现那些sign根本没变化。

看了别人的代码,我发现:一般大家都是先修改sign,再调用/遍历元素的!

 

13. hdu 1280(求n个元素中任意两个的和中,前m大的元素)

在命名变量的时候,尽量不要用data。data()是c++中部分类的一个函数。比如在string中,c_str()和data():生成一个const char*指针,指向一个临时数组。因此,有时会报错:什么定义不明确之类的问题。

14.hdu 4245

这里的问题在于,map的Insert()如何使用,我们应该这样用:map.insert(make_pair(a,b));

 

14.hdu 4246

首先是对题目意思的理解,一定不能有偏差,否则咋做得出呢!!!

论打表的技术

这里在计算出来所有的飞机各个机位出发的序列之后(1344种),由于实际共有3^8 = 6561种初始的停放飞机的状态,因此还需要计算在每种初始状态下,所有可能的出发序列最终可以产生多少种不同的出发方式。因为飞机只有两种颜色,所以实际上只需要将这两种飞机的颜色记做二进制(这样不停飞机的位置就自动被消灭掉了),然后统计他们出现的次数。

位运算符优先级低于加减乘除!

 

15.hdu 4248 

常用动态规划解决这类排列组合问题。这里构造动态规划的状态迁移方程是难点:考虑前i种石头中,已经选取了j个石头,能放出的方法数有dp[i][j]种。其中,第i种石头可以选取0~stone[i]个,stone[i] <= j.假设已经选取了k个。而对于前面dp[i-1][j]中的任意一种情况,我们可以都可以安排c(j,k)种排法,所以dp[i][j] = sum(dp[i-1][j-k] * C(j,k)).

一般来说,排列组合的题目也是需要打表的。

比较麻烦的地方一个是求组合数。需要控制组合数的生成的量。

然后是动态规划中最常见的问题,就是数组在初始化的时候长度+1会比较好做。

然后是变量的范围,这里尤其要注意!比如说k指代什么,如果k是指代前i-1中石头我们选择的颗数,那么k <= j && k ?= max(0,j-stones[i])。那么其时k的值得变化范围可以从j开始往下取,这样方便不少。

最后是建立起结果与dp数组的关系,这也很重要。

16.hdu 4256

水题。。。

做题的时候,尤其是那种限时做题的时候,一般来说大多数人都去做,或者都能做出来的题目往往比较简单,可以先考虑解决。

17.hdu 4249(真让人意想不到,这题竟然是动态规划题!!!)

这类题属于数位Dp。是一类经典算法。

提一下scanf()的返回值,它返回的是该函数按照规范读入数据时读入的个数。

这道题难点在于临界条件的判断。

平时使用三目运算符?:的时候,建议多加括号,因为运算符的优先级有时候很容易弄混。

另外,long long类型我们通常写成:

typedef long long LL;

18. hdu 4254 均匀先验问题 https://www.cnblogs.com/hilbertan/archive/2012/11/09/2761893.html

19.poj 3255

邻接链表的写法:(以dijkstra为例)

#include<queue>
#include<functional>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
#define EDGE_NUM 100005//边的数目上限
#define NODE_NUM 5005//节点数目上限
#define MAX_INT INT_MAX//边的权重上限

int edge_index[NODE_NUM],min_dist[NODE_NUM];//前者用来存储以节点i为出发点的各条边
//邻接链表的初始边的序号;后者用来存储源节点到各个节点的最短距离
int edge_num;//存储边的数目,同时也可作为边的序号

typedef pair<double,int>P;//前面是每个点的当前的距离,后面则是各个点的序号,
//用这种方式存储便于放在队列中进行比较
struct Edge//采用类的数组来存储边,这种邻接链表的存储边的方式在稀疏表中存储效率
//要高于邻接矩阵,邻接矩阵适合存储密集图
{
    int source,int target,int weight;
    int next;//记录每个节点的上一条同样以source为出发点的边的边序号
}edges[EDGE_NUM*2];//这里注意需要将边数乘以2,因为图是无向图;如果是有向图,则
//无需乘法操作

void add_edge(int sta_p,int end_p,int wei)//添加边到边的数组
{
    edges[edge_num].source = sta_p;
    edges[edge_num].target = end_p;
    edges[edge_num].weight = wei;
    edges[edge_num].next = edge_index[sta_p];
    edge_index[sta_p] = edge_num++;//因此这里需要更新这个初始边的序号
}

void dijkstra(int sta)
{
    priority_queue<P,vector<P>,greater<P> >graphs;
    min_dist[sta] = 0;
    graphs.push(make_pair(0,sta));
    
    while(graphs.size())
    {
        P temp = graphs.top();
        graphs.pop();
        if(temp.first > min_dist[temp.second])
            continue;
        for(int i = edge_index[temp.second];i != -1;i = edges[i].next)
        {
            int node_weight = edges[i].weight;
            int node_target = edges[i].target;
            if(min_dist[node_target] > min_dist[temp.second]+node_weight)
            {
                min_dist[node_target] = min_dist[temp.second]+node_weight;
                graphs.push(make_pair(min_dist[node_target],node_target));
            }
        }
    }
}

int main()
{
    //get the nubmer of nodes and roads......

    memset(edge_index,-1,sizeof(edge_index));
    for(int i = 1;i <= the_number_of_nodes;++i)
    {
        min_dist[i] = MAX_INT;
    }
    
    //add_edges.....
    dijkstra(sta_point);
}

19题延伸:求次短路径并打印(校数据结构上机题)

Problem 3 : 第二短路径 1) 问题描述: 求有向图的指定起始点和指定终点的第二短路径。第二短路径指的从起始点到终点的最 短路径外的另一条最短路径,假如该有向图存在多条最短路径,则第二短路径的路径总长度 和最短路径相同。若存在多条第二短路径,输出所有第二短路径。若不存在第二短路径,即 起始点与终点路径小于两条,则输出“no path”。 2) 输入: 数据从屏幕输入,第一行为测试用例的个数,从第二行开始为每个测试用例的信息。对 每一个测试用例来说,第一行为有向图顶点数 m(顶点编号从 0 开始),第二行为有向 图边数 n,接下来为 n 行为边的起点、终点和权重,最后一行为所要求的第二短路径的 起始点和终点。 3) 输出:控制台输出,输出每个测试用例结果,每一个测试用例结果占一行。若存在第二 短路径输出相应路径,若存在多条路径,则在同一行输出,空格隔开,输出顺序无要求 (我们会人工进行判别)。若不存在第二短路径则输出“no path”。 4) 输入、输出举例: 上传文件请命名为 problem3.cpp 或其他相应后缀:problem3.相应后缀。

输入: 3 3 2 0 1 1 1 2 2 1 0 4 4 0 2 2 2 3 3 0 1 2 1 3 3 0 3 4 4 0 2 2 2 3 3 0 1 3 1 3 3 0 3

输出: 5 no path 0->1->3 0->2->3 0->1->3 5)

数据规模: 顶点数<=1000,边数<=10000,时间限制为 20s。

#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<set>
#include<string>
#include<functional>
#include<vector>
#define EDGE_NUM 100005
#define NODE_NUM 5005	
#define MAX_INT 2147483647
using namespace std;
int N, R;
int edge_index[NODE_NUM],edge_index2[NODE_NUM];
int min_dist_1[NODE_NUM], min_dist_2[NODE_NUM];
int parent_node[NODE_NUM],parent_node2[NODE_NUM];
int edge_num,edge_num2;

typedef pair<int, int>P;

struct Edge
{
	int source,target,weight;
	int next;
}edges[EDGE_NUM],edges2[EDGE_NUM];

void add_edge(int sta_p, int end_p, int wei)
{
	edges[edge_num].source = sta_p;
	edges[edge_num].target = end_p;
	edges[edge_num].weight = wei;
	edges[edge_num].next = edge_index[sta_p];
	edge_index[sta_p] = edge_num++;
}

void add_edge2(int sta_p, int end_p, int wei)
{
	edges2[edge_num2].source = sta_p;
	edges2[edge_num2].target = end_p;
	edges2[edge_num2].weight = wei;
	edges2[edge_num2].next = edge_index2[sta_p];
	edge_index2[sta_p] = edge_num2++;
}

void dijkstra(int sta)
{
	priority_queue<P,vector<P>, greater<P> >graphs;
	min_dist_1[sta] = 0;
	graphs.push(make_pair(0,sta));
	while (graphs.size())
	{
		P temp = graphs.top();
		graphs.pop();
		if (temp.first > min_dist_1[temp.second])
			continue;
		for (int i = edge_index[temp.second]; i != -1; i = edges[i].next)//i depicts the index of edge(from 1 to 2*R)whose terminal vertex is temp
		{
			int node_weight = edges[i].weight;
			int node_target = edges[i].target;
			if (min_dist_1[node_target] > min_dist_1[temp.second] + node_weight)
			{
				min_dist_1[node_target] = min_dist_1[temp.second] + node_weight;
				parent_node[node_target] = temp.second;
				graphs.push(make_pair(min_dist_1[node_target],node_target));
			}

		}
	}
}

void dijkstra2(int sta)
{
	priority_queue<P, vector<P>, greater<P> >graphs;
	min_dist_2[sta] = 0;
	graphs.push(make_pair(0, sta));
	while (graphs.size())
	{
		P temp = graphs.top();
		graphs.pop();
		if (temp.first > min_dist_2[temp.second])
			continue;
		for (int i = edge_index2[temp.second]; i != -1; i = edges2[i].next)//i depicts the index of edge(from 1 to 2*R)whose terminal vertex is temp
		{
			int node_weight = edges2[i].weight;
			int node_target = edges2[i].target;
			if (min_dist_2[node_target] > min_dist_2[temp.second] + node_weight)
			{
				min_dist_2[node_target] = min_dist_2[temp.second] + node_weight;
				parent_node2[node_target] = temp.second;
				graphs.push(make_pair(min_dist_2[node_target], node_target));
			}

		}
	}
}

int main()
{
	int case_num;
	scanf_s("%d",&case_num);
	for (int i = 0; i < case_num; ++i)
	{
		set<string>results_fir,results_sec;
		scanf_s("%d",&N);
		scanf_s("%d",&R);
		edge_num = edge_num2 = 0;
		memset(edge_index, -1, sizeof(edge_index));
		memset(parent_node, -1, sizeof(parent_node));
		memset(edge_index2, -1, sizeof(edge_index2));
		memset(parent_node2, -1, sizeof(parent_node2));
		for (int i = 0; i < N; ++i)
		{
			min_dist_1[i] = min_dist_2[i] = MAX_INT;
		}
		//initialize Roads
		for (int i = 0, sta_p, end_p, wei; i < R; ++i)
		{//index start from 1 to N 
			scanf_s("%d%d%d", &sta_p, &end_p, &wei);
			add_edge(sta_p, end_p, wei);
			add_edge2(end_p, sta_p, wei);
		}

		int graph_sta, graph_end;
		scanf_s("%d%d",&graph_sta,&graph_end);

		dijkstra(graph_sta);
		dijkstra2(graph_end);

		//to store least and second least longest routes 
		int sec_min = MAX_INT;//the second least length among all the routes
		for (int i = 0; i < R; i++)
		{
			int temp_sta = edges[i].source;
			int temp_end = edges[i].target;
			int temp_wei = edges[i].weight;
			int sums = min_dist_1[temp_sta] + min_dist_2[temp_end] + temp_wei;
			if (sums == min_dist_1[graph_end])//record:sta->temp_sta->temp_end->end
			{
				string temp_res = to_string(temp_sta);
				int fir_list = parent_node[temp_sta];
				while (fir_list != -1)
				{
					temp_res = to_string(fir_list)+"->"+temp_res;
					fir_list = parent_node[fir_list];
				}

				temp_res += "->"+to_string(temp_end);
				int sec_list = parent_node2[temp_end];
				while (sec_list != -1)
				{
					temp_res = temp_res + "->" + to_string(sec_list);
					sec_list = parent_node2[sec_list];
				}
				results_fir.insert(temp_res);
			}
			else if (sums < sec_min && sums > min_dist_1[graph_end])
			{
				sec_min = sums;
				string temp_res = to_string(temp_sta);
				int fir_list = parent_node[temp_sta];
				while (fir_list != -1)
				{
					temp_res = to_string(fir_list) + "->" + temp_res;
					fir_list = parent_node[fir_list];
				}

				temp_res += "->" + to_string(temp_end);
				int sec_list = parent_node2[temp_end];
				while (sec_list != -1)
				{
					temp_res = temp_res + "->" + to_string(sec_list);
					sec_list = parent_node2[sec_list];
				}
				results_sec.insert(temp_res);
			}
		}

		int least_num = results_fir.size(), sec_num = results_sec.size();
		if (least_num > 1)
		{
			for (set<string>::iterator s_i = results_fir.begin(); s_i != results_fir.end(); ++s_i)
				cout << *s_i << " ";
			cout << endl;
		}
		else if (least_num == 1 && sec_num)
		{
			for (set<string>::iterator s_i = results_sec.begin(); s_i != results_sec.end(); ++s_i)
				cout << *s_i << " ";
			cout << endl;
		}
		else
			cout << "no path" << endl;
	}

	return 0;
}

20.Hilbert曲线变换

Problem 4:Hilbert 曲线转换 1) 问题描述 Hilbert 曲线是德国数学家 David Hilbert 发明的一种连续的空间填充曲线,它能将高维空间 映射到一维空间,同时在一维空间上保留了原高位空间的良好局部性。目前 Hilbert 曲线被 广泛应用于图像存储和检索、空间数据库索引等领域。 对于二维空间,假设有 N*N 个方格(N= 2d ,d 为正整数),Hilbert 曲线以某种顺序不自交 地通过每个方格的中心点一次且仅一次,填满 N*N 个方格。并从 1 开始,按照填充顺序依 次为每个方格分配一个 ID,称为 Hilbert 值。图 4-1 和 4-2 为 2*2 和 4*4 方格矩阵的 Hilbert 曲线以及每个方格的 Hilbert 值,图 4-3 和 4-4 为 8*8 和 16*16 方格矩阵的 Hilbert 曲线(Hilbert 值未标出)。 1 2 4 3 图 4-1 图 4-2 图 4-3 图 4-4 Hilbert 曲线的填充规律具体如下: (a) 对于 2*2 的方格矩阵,按 NW‐NE‐SE‐SW 的顺序填充四个方格得到 Hilbert 曲线,如 图 4‐1 所示; 7 (b) 假设当前已经知道 2i * 2i 的方格矩阵的 Hilbert 曲线形状 Hi,那么对于 2i+1    * 2i+1的 方格矩阵,先将该方格矩阵看成四个 2i * 2i 的方格矩阵,按照 NW‐NE‐SE‐SW 的顺序 填充这四个方格矩阵;其中,NW、NE、SE、SW 方格矩阵的曲线形状分别为 2i * 2i 的方格矩阵的 Hilbert 曲线 Hi 顺时针旋转 90°,逆时针旋转 0°、0°、90°得到。 现在给定一个 N*N 的二维矩阵,要求对矩阵进行 hilbert 转换,求出某个方格的 hilbert 值。 2) 输入及示例 数据从屏幕输入,第一行为测试用例的个数,从第二行开始为每个测试用例的值。每个测试 用例包括 2 行,第一行为矩阵的边长 N,注意 N 一定是 2 的幂,第二行为需要输出 Hilbert 值的方格的坐标 i 和 j,i 和 j 分别表示方格的行数和列数。规定最上一行为第 0 行,最左一 列为第 0 列,即矩阵的左上角方格坐标为(0, 0)。如对于图 4-1 和 4-2 例子,屏幕输入内容如 下: 2 2 1 1 4 1 2 3)输出及示例 上传文件请命名为 problem4.cpp 或其他相应后缀:problem4.相应后缀。 程序运行后,结果输出到屏幕上。输出内容为方格矩阵的第 i 行第 j 列的方格的 Hilbert 值,每个测试用例的结果占一行。以上图为例,输出结果为: 3 8 4)数据规模 矩阵边长 N<=210,时间限制 20s。

#include "stdafx.h"//核心是建立映射关系
#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<set>
#include<string>
#include<functional>
#include<vector>
using namespace std;

int transfer(int types,int val)
{
	if (types == 0)
	{
		if (val % 2)
			return 4 - val;
		else
			return val;
	}
	if (types == 3)
	{
		if (val % 2)
			return val;
		else
			return 4 - val;
	}
	return val;
}

int main()
{
	int case_num, side_len, cor_x, cor_y;
	scanf_s("%d",&case_num);
	for (int i = 0; i < case_num; ++i)
	{
		scanf_s("%d",&side_len);
		scanf_s("%d%d",&cor_x,&cor_y);
		int totals = side_len * side_len;
		int len_t = side_len / 2;
		string swall = "";
		while (len_t)
		{
			cout << "coor:" << cor_x << " " << cor_y << endl;
			int temp_x = cor_x/len_t;
			int temp_y = cor_y/len_t;
			cor_x %= len_t;
			cor_y %= len_t;
			len_t /= 2;
			if (temp_x == 0)
			{
				if (temp_y == 0)
					swall += '0';
				else
					swall += '1';
			}
			else
			{
				if (temp_y == 0)
					swall += '3';
				else
					swall += '2';
			}
		}

		//cout << swall << endl;
		int s_len = swall.size();
		string new_str = "";
		new_str += swall[0];
		for (int i = 0; i < s_len-1; ++i)
		{
			new_str += char('0' + transfer(new_str[i]-'0',swall[i+1]-'0'));
		}
		//cout << new_str << endl;
		int res = totals,counter = 0;
		while (counter < s_len)
		{
			res /= 4;
			res *= new_str[counter] - '0' + 1;
			counter++;
		}
		cout << res << endl;
	}
}

21.poj 3522 最大权重边和最小权重边的差值最小的“最小生成树”

一开始我的思路是暴力地遍历图中所有的最小生成树,复杂度应该是O(C(E,V)*E*lg(V))。显然这是不可接受的。

然后我转而考虑:先生成一棵最小生成树,再通过加边删边的操作来迭代找结果。举了一个反例,发现这种贪心的算法是找不到最优解的。

最后看了网上的做法:采用kruskal算法,先给边按权重排序,枚举最小权重边,生成最小生成树,找最优解。因为每次在生成最小生成树的时候,找出的最后一条边是剩余边中当前权值最小的一条,所以相当于生成了以第i条边为最小权重边的slim spanning tree.时间复杂度是O(E^2*lg(V)).

#include<algorithm>
#include<cstdio>
#define NODE_NUM 105
#define EDGE_NUM NODE_NUM*(NODE_NUM-1)/2
using namespace std;
int N,R,num_edge,node_counter;
struct EDGE
{
    int source,target,weight;
}edges[EDGE_NUM];

//the function model for sets forest
int parents[NODE_NUM];//stored for their parents

const bool cmp(const EDGE &a,const EDGE &b)
{
    return a.weight < b.weight;
}

int find_parent(int x)//notice: don't use while here, use if instead
{
    if(x != parents[x])
    { 
        parents[x] = find_parents(parents[x]);
    }
    return parents[x];
}

int merge(int x,int y)
{
    int px = find_parents(x),
        py = find_parents(y);
    if(px != py)
    {
        parents[px] = py;
        node_counter--;
    } 
    if(node_counter)
        return -1;
    return 0;//have constructed the minimal spanning tree
}   

int main()
{
    while(scanf("%d%d",&N,&R) != EOF)
    {
        if(N == 0)
        {
            break;
        }
        num_edge = 0;
        memset(edges,0,sizeof(edges));
        for(int ei = 0,fir,sec,wei;ei < R;++ei)
        {
            scanf_s("%d%d%d",&fir,&sec,&wei);
            edges[num_edge].source = fir;
            edges[num_edge].target = sec;
            edges[num_edge].weight = wei;
            num_edge++;
        }

        sort(edges,edges+R,cmp);
        for(int i = 1;i <= N;++i)
            parents[i] = i;
        
        int signal = 1;
        for(int i = 0;i < R;++i)
        {
            if(0 == merge(edges[i].source,edges[i].target))
                break;
        }
    }
}

22.NOIP 2002 矩形覆盖(洛谷oj 1034)

这题由于数据非常水,因此从AC题目为目的来看,这题简单,但是这题实际上是比较复杂的。

首先,考虑到平面上只有不超过4个矩形,因此我们完全可以通过分类讨论的方式来解决问题。不过这种思路还是太暴力了,不推荐这么做。

一种暴力美学式的做法是,考虑每一个节点出现在每一个矩形中的情况(若该矩形尚且不存在,则用该点表示该矩形,否则将该点添加到该矩形之中,修改矩形的上下左右界限),用dfs进行搜索,搜索对象是节点,因此至多n层(不超过50)。50层已经很夸张了,因此我们要考虑剪枝,也即在某些分支出现了明显不符条件的特征时,将其舍去。

从上面的分析中,我们很快就能得出代码的大致思路:

#include<cstdio>
#include<algorithm>
using namespace std;

struct dot //点的坐标
{
	int x, y;
}a[51];

struct M 
{
	int l, r, u, d;//矩形的上下左右四条边的范围
	bool fl;
}p[5];
int n, m, ans = 1e9, i;

bool in(M a, int x, int y) //点(x,y)是否在矩形a中,若在则返回true
{
	return x >= a.l && x <= a.r && y >= a.d && y <= a.u;
}

bool judge(M a, M b) //矩形a,b是否有交点,若有则返回true
{
	return in(a, b.l, b.u) || in(a, b.l, b.d) || in(a, b.r, b.u) || in(a, b.r, b.d);
}

void dfs(int num) //num表示第num个节点
{
	int val = 0;
	for (int i = 1; i <= m; i++) //i表示第i个矩形
	{
		if (p[i].fl)//该矩形存在
		{
			for (int j = i + 1; j <= m; j++)
			{
				if (judge(p[i], p[j]))//两个矩形相交,该情况不符条件,舍去
					return;
			}
		}
		val += (p[i].r - p[i].l)*(p[i].u - p[i].d);//计算矩形的面积之和
	}
	if (val >= ans) //剪枝
		return;
	if (num>n) //所有点都已经遍历过了
	{
		ans = val;
		return;
	}
	for (int i = 1; i <= m; i++) //暴力搜索,就是将每个点属于每个矩形的情况都计算一遍
	{
		M tmp = p[i];//保存当前的第i个矩形的状态,用来做回溯
		if (!p[i].fl) //如果该矩形尚且不存在,则先用一个节点构建出该矩形
		{
			p[i].fl = 1;
			p[i].l = p[i].r = a[num].x;
			p[i].u = p[i].d = a[num].y;
			dfs(num + 1);
			p[i] = tmp;//这里将第i个矩形的值返回原样,从而进行回溯(这里的回溯,是说在完成了上面一句的dfs这个分支之后,
			//先将第i个矩形的状态恢复原状,然后进入下一次循环)
			break;//需要保证之前每个矩形都存在,否则之后进入的点将有可能不存在于某个矩形之中,一种必须的剪枝手段
		}
		else //该矩形已经存在,就是说该矩形已包含至少一个点了,这时我们将该点添到这个矩形中
		{
			p[i].r = max(p[i].r, a[num].x);
			p[i].l = min(p[i].l, a[num].x);
			p[i].u = max(p[i].u, a[num].y);
			p[i].d = min(p[i].d, a[num].y);
			dfs(num + 1);
			p[i] = tmp;
		}
	}
}

int main() 
{
	scanf_s("%d%d", &n, &m);
	for (i = 1; i <= n; i++) 
		scanf_s("%d%d", &a[i].x, &a[i].y);
	dfs(1);
	printf("%d", ans);
}

23.hdu 2005,1201(关于日期计算)

在visual studio中,终止输入可以使用ctrl+z,停止程序运行可以使用ctrl+c.

#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
string todays;
int T;
int LY[2][12] = {31,28,31,30,31,30,31,31,30,31,30,31,31,29,31,30,31,30,31,31,30,31,30,31 };

int IsLeapYear(int years)
{
	if (years % 400 == 0)
		return true;
	else if (years % 100 == 0)
		return false;
	else if (years % 4 == 0)
		return true;
	return false;
}

int main()
{
	while (scanf_s("%d",&T) != EOF)
	{
		for(int di = 0;di < T;++di)
		{
			cin >> todays;
			int years = 0, months = 0, days = 0;
			int i = 0;
			for (; i < todays.size() && todays[i] != '-'; ++i)
			{
				years *= 10;
				years += todays[i] - '0';
			}
			i++;
			for (; i < todays.size() && todays[i] != '-'; ++i)
			{
				months *= 10;
				months += todays[i] - '0';
			}
			i++;
			for (; i < todays.size() && todays[i] != '-'; ++i)
			{
				days *= 10;
				days += todays[i] - '0';
			}

			//to judge if he has 18-th birthday or not
			if (IsLeapYear(years) && months == 2 && days == 29)
			{
				cout << -1 << endl;
				continue;
			}

			int res = 0;
			//to calculate the mid time first
			for (int i = 1; i < 18; ++i)
			{
				if (IsLeapYear(years + i))
					res += 366;
				else
					res += 365;
			}
			//to add head
			int signal_h = IsLeapYear(years),
				signal_t = IsLeapYear(years+18);
			for (int i = months + 1; i <= 12; ++i)
			{
				res += LY[signal_h][i - 1];
			}
			res += LY[signal_h][months - 1];

			//to add tail
			for (int i = 1; i < months; ++i)
			{
				res += LY[signal_t][i - 1];
			}
			cout << res << endl;
		}
	}

	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值