8月10日训练总结 POJ2148 HDU2553 HDU3294

计算几何+DFS

POJ2148Color the Map

每个国家是一个或多个多边形,给出每个国家各个顶点的坐标,相邻国家不能同色,求最少的染色数量。

完全不知道自己错在哪里,感觉没有问题,但就是不对。

留个记号,日后补题。

判断重合我用的方法是,

先判断共线

假设一条边是p,两个点分别为p1,p2,另一条边是q,两个点是q1,q2,那么当

p*q=0

(p1-q1)*p=0

时,p,q在一条直线上,第一个公式说明p,q平行,第二个公式说明q1在p所在的直线上,所以p,q共线。

再判断重合

int minpx=min(p1.x,p2.x),minqx=min(q1.x,q2.x),maxpx=max(p1.x,p2.x),maxqx=max(q1.x,q2.x);
int minpy=min(p1.y,p2.y),minqy=min(q1.y,q2.y),maxpy=max(p1.y,p2.y),maxqy=max(q1.y,q2.y);
	if(minpx==maxpx)
		if(minpy>=maxqy||minqy>=maxpy)
			return 0;
		else
			return 1;
	else 
		if(minpx>=maxqx||minqx>=maxpx)
			return 0;
		else	
			return 1;

minpx,minqx表示p,q最左边,maxqx,maxpx表示最右边,一条竖直线的时候去比较y,其他时候比较x即可,一条边最左边大于等于另一条边的最右边,那么一定不重合。注意等于的情况。这道题里点相邻是不算的

但是这个方法会判多,希望日后有大佬帮我指证出来,万分感谢!

#include <cstdio>
#include <vector>
#include <map>
#include <string>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
struct point
{
	int x,y;
	point(int _x,int _y):x(_x),y(_y){}
 	int operator * (const point &b) const{	
		return x*b.y-y*b.x;
	}
 	point operator - (const point &b) const{	
		return point(x-b.x,y-b.y);
	}
 	bool operator != (const point &b) const{
 		return x!=b.x||y!=b.x;
 	}
 	point operator + (const point &b) const{
 		return point(x+b.x,y+b.y);
	}
}; 
map<string,int>name;//图形 
int m[15][15];
int vis[15],num[15]; 
bool judge(point p1,point p2,point q1,point q2)
{
	int minpx=min(p1.x,p2.x),minqx=min(q1.x,q2.x),maxpx=max(p1.x,p2.x),maxqx=max(q1.x,q2.x);
	int minpy=min(p1.y,p2.y),minqy=min(q1.y,q2.y),maxpy=max(p1.y,p2.y),maxqy=max(q1.y,q2.y);
	if(minpx==maxpx)
		if(minpy>=maxqy||minqy>=maxpy)
			return 0;
		else
			return 1;
	else 
		if(minpx>=maxqx||minqx>=maxpx)
			return 0;
		else	
			return 1;
} 
void dfs(int x)
{
	int cnt;
	memset(num,0,sizeof(num));
	for(int i=1;i<=10;i++)
		if(m[x][i])
			num[vis[i]]=1;
	for(int i=1;i<=10;i++)
		if(num[i]==0)
		{
			vis[x]=i;
			break;
		}
	for(int i=1;i<=10;i++)
		if(m[x][i]&&vis[i]==0)
			dfs(i);
}
int main()
{
	int n;
	string s;
	while(scanf("%d",&n)&&n)
	{
		name.clear();
		vector<point>p[15];//点 
		vector<point>b[15];//边 	
		memset(m,0,sizeof(m));
		int pos,x,y,start,cnt=1;
		for(int ii=1;ii<=n;ii++)
		{
			cin>>s;
			if(!name[s])
				pos=cnt++,name[s]=pos,start=0;
			else
				pos=name[s],start=p[pos].size();
			while(scanf("%d",&x)&x!=-1)
			{
				scanf("%d",&y);
				p[pos].push_back(point(x,y));
			}
			for(int i=start+1;i<p[pos].size();i++)
				b[pos].push_back(p[pos][i]-p[pos][i-1]);
			b[pos].push_back(p[pos][start]-p[pos][p[pos].size()-1]);
			for(map<string,int>::iterator it=name.begin();it!=name.end();it++)
			{
				int itt=it->second;
				if(itt==pos||m[itt][pos])
					continue;
				for(int i=0;i<b[itt].size()&&m[itt][pos]==0;i++)
					for(int j=start;j<b[pos].size()&&m[itt][pos]==0;j++)
					{
						point p1=p[itt][i],p2=p1+b[itt][i];
						point q1=p[pos][j],q2=q1+b[pos][j];
						if(b[itt][i]*b[pos][j]==0&&(p1-q1)*b[itt][i]==0)
							if(judge(p1,p2,q1,q2))//注意顶点相连不算,边重合的情况 
								m[itt][pos]=m[pos][itt]=1;//注意双向边,别写成单向边 
					}	
			}
		}
		memset(vis,0,sizeof(vis));
		int flag=0;
//		for(int i=1;i<=10;i++)
//		{
//			for(int j=1;j<=10;j++)
//			cout<<m[i][j]<<' ';
//			cout<<endl;
//		}
		dfs(1);
		for(int i=1;i<=10;i++)
		 	flag=max(flag,vis[i]);
		printf("%d\n",flag);	
	}
}

再贴一组测试数据,来自http://blog.sina.com.cn/s/blog_680c5cd50100kl8d.html

24
C1
47 39
61 39
61 12
47 12
-1
C2
220 73
228 73
228 74
229 74
229 75
236 75
236 12
220 12
-1
C3
114 46
116 46
116 47
117 47
117 49
118 49
118 50
120 50
120 51
121 51
121 53
122 53
122 54
124 54
124 55
125 55
125 57
126 57
126 58
128 58
128 60
129 60
129 61
130 61
130 62
132 62
132 64
133 64
133 65
134 65
134 68
136 68
136 69
137 69
137 70
138 70
138 72
139 72
139 73
141 73
141 76
151 76
151 65
149 65
149 63
148 63
148 62
147 62
147 60
146 60
146 59
144 59
144 58
143 58
143 55
142 55
142 53
140 53
140 52
139 52
139 51
138 51
138 50
137 50
137 48
135 48
135 47
134 47
134 45
132 45
132 44
131 44
131 43
130 43
130 41
129 41
129 40
127 40
127 39
126 39
126 37
125 37
125 36
114 36
-1
C4
28 51
46 51
46 41
47 41
47 39
28 39
-1
C5
47 41
46 41
46 51
60 51
60 39
47 39
-1
C6
60 51
80 51
80 39
60 39
-1
C7
91 44
90 44
90 46
89 46
89 47
88 47
88 49
87 49
87 51
86 51
86 53
85 53
85 56
84 56
84 71
94 71
94 66
95 66
95 62
96 62
96 60
97 60
97 58
98 58
98 57
99 57
99 55
100 55
100 53
101 53
101 40
91 40
-1
C8
46 52
45 52
45 54
44 54
44 55
43 55
43 56
42 56
42 58
41 58
41 59
40 59
40 62
39 62
39 63
37 63
37 64
36 64
36 66
35 66
35 69
34 69
34 70
32 70
32 71
31 71
31 72
42 72
42 73
61 73
61 74
66 74
66 71
65 71
65 70
64 70
64 66
63 66
63 65
61 65
61 51
46 51
-1
C9
104 58
103 58
103 64
102 64
102 69
101 69
101 72
100 72
100 76
98 76
98 81
97 81
97 84
98 84
98 83
102 83
102 84
107 84
107 85
110 85
110 79
111 79
111 76
112 76
112 71
113 71
113 68
114 68
114 56
104 56
-1
C1
31 73
30 73
30 74
29 74
29 76
27 76
27 78
26 78
26 81
25 81
25 83
24 83
24 85
23 85
23 87
22 87
22 88
21 88
21 91
20 91
20 95
19 95
19 97
18 97
18 107
28 107
28 106
29 106
29 105
30 105
30 101
31 101
31 98
32 98
32 96
33 96
33 93
35 93
35 90
36 90
36 88
37 88
37 84
39 84
39 83
40 83
40 81
41 81
41 80
42 80
42 79
44 79
44 76
45 76
45 75
46 75
46 73
42 73
42 72
31 72
-1
C0
47 87
62 87
62 90
64 90
64 92
65 92
65 94
66 94
66 95
67 95
67 97
69 97
69 99
70 99
70 100
71 100
71 102
82 102
82 87
80 87
80 86
77 86
77 85
76 85
76 84
75 84
75 83
74 83
74 82
73 82
73 80
72 80
72 79
71 79
71 77
69 77
69 75
68 75
68 74
61 74
61 73
47 73
-1
C1
220 115
229 115
229 116
235 116
235 115
236 115
236 75
229 75
229 74
228 74
228 73
220 73
-1
C9
270 107
285 107
285 74
270 74
-1
C4
177 95
192 95
192 77
177 77
-1
C2
98 84
97 84
97 85
96 85
96 87
95 87
95 90
94 90
94 93
93 93
93 94
92 94
92 101
91 101
91 103
90 103
90 108
88 108
88 111
87 111
87 113
86 113
86 115
100 115
100 112
101 112
101 107
102 107
102 103
103 103
103 98
105 98
105 96
106 96
106 94
107 94
107 88
108 88
108 85
107 85
107 84
102 84
102 83
98 83
-1
C6
47 100
55 100
55 101
59 101
59 100
61 100
61 88
62 88
62 87
47 87
-1
C5
119 105
120 105
120 107
121 107
121 109
123 109
123 110
124 110
124 113
125 113
125 115
85 115
85 128
132 128
132 130
133 130
133 132
134 132
134 133
145 133
145 123
144 123
144 122
143 122
143 121
142 121
142 119
140 119
140 117
139 117
139 115
138 115
138 110
137 110
137 106
135 106
135 104
134 104
134 103
133 103
133 100
132 100
132 99
131 99
131 98
130 98
130 96
129 96
129 95
119 95
-1
C8
177 115
179 115
179 114
180 114
180 115
192 115
192 95
177 95
-1
C3
47 112
55 112
55 113
61 113
61 100
59 100
59 101
55 101
55 100
47 100
-1
C0
270 115
269 115
269 118
268 118
268 129
269 129
269 132
285 132
285 107
270 107
-1
C2
47 132
61 132
61 113
55 113
55 112
47 112
-1
C7
179 115
177 115
177 116
175 116
175 131
206 131
206 115
180 115
180 114
179 114
-1
C3
206 131
227 131
227 126
226 126
226 116
227 116
227 115
206 115
-1
C0
227 116
226 116
226 126
227 126
227 131
269 131
269 129
268 129
268 118
269 118
269 115
235 115
235 116
229 116
229 115
227 115
-1
0

结果是4,我跑出来是5。

HDU2553N皇后问题

N皇后问题,经典DFS。

1、对角线有两种,一种左斜下来,一种右斜下来。

斜45度线的性质:

1、一般成对出现

2、一种方向的x+y为定值,另一种x-y为定值

2、注意记忆化,否则会超时!

这种结果固定的还多组输入输出注意记忆去省时间

#include <cstdio>
#include <cstring>
using namespace std;
bool v1[15],v2[25],v3[25],vis[15];
int n,cnt,ans[15];
void dfs(int x)
{
	if(x==n+1)
	{
		cnt++;
		return ;
	}
	for(int i=1;i<=n;i++)
	{
		if(!v1[i]&&!v2[x-i+n]&&!v3[x+i])
		{
			v1[i]=1;
			v2[x-i+n]=1;
			v3[x+i]=1;
			dfs(x+1);
			v1[i]=0;
			v2[x-i+n]=0;
			v3[x+i]=0;
		}
	}	
}
int main()
{
	memset(ans,0,sizeof(ans));
	memset(vis,0,sizeof(vis));
	while(scanf("%d",&n)&&n)
	{
		if(!vis[n])
		{
			cnt=0;
			memset(v1,0,sizeof(v1));
			memset(v2,0,sizeof(v2));
			memset(v3,0,sizeof(v3));
			dfs(1);
			printf("%d\n",cnt);
			ans[n]=cnt;
			vis[n]=1;
		}
		else
			printf("%d\n",ans[n]);
		
	}
} 

manacher模板

HDU3294Girls' research

找到最长回文字串并输出,不过初始化需要统一改变一下字符串。

不知道为什么,一直WA,后来改了一下输出,就过了,很迷。

+-运算优先级高于位运算符

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int N=2e6+5;
char s0[2],s[N],ans[N<<1];//ans加工后字符串 
int res[N<<1],maxn;//回文串长度字符串 
int add(char s[])
{
	int l=strlen(s);
	ans[0]='@';
	for(int i=1;i<=(l<<1);i+=2)
	{
		ans[i]='#';
		ans[i+1]=s[i/2];
	}
	ans[(l<<1)+1]='#';
	ans[(l<<1)+2]='$';
	ans[(l<<1)+3]='\0';
	return (l<<1)+1;
}
int manacher(char s[],int l)
{
	int mx=0,po=0,p;
	maxn=0;
	for(int i=1;i<=l;i++)
	{
		if(mx>i)
			res[i]=min(mx-i,res[(po<<1)-i]);
		else
			res[i]=1;
		while(s[i-res[i]]==s[i+res[i]])
			res[i]++;
		if(mx<res[i]+i)
		{
			po=i;
			mx=res[i]+i;
		}
		if(res[i]>maxn)
		{
			maxn=res[i];
			p=i;
		}
	}
	return p;//maxn-1是原串最长回文串长度,p/2-1是maxn-1为奇数时的中心位置 ,偶数时的左中心 
}
int main()
{
	while(~scanf("%s",s0))
	{
		scanf("%s",s);
		int d='a'-s0[0];
		int l=strlen(s);
		for(int i=0;i<l;i++)
		{
			if(s[i]+d<'a')
			 	s[i]=s[i]+26+d;
			else
				s[i]=s[i]+d;
		}
		int p=manacher(ans,add(s));
		maxn--;
		if(maxn==1)
			printf("No solution!\n");
		else
		{ 
			int l=(p-maxn+1)/2-1,r=(p+maxn-1)/2-1; 
				printf("%d %d\n",l,r);
			for(int i=l;i<=r;i++)
				printf("%c",s[i]);
			printf("\n");
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值