ACM算法专用模板(持续更新中)

标签:位运算,gcd,exgcd,欧拉筛,快速乘,矩阵快速幂,中国剩余定理,欧拉函数,逆元,高斯消元,母函数,斯特林数,卡特兰数,莫比乌斯反演,SG函数与Nim博弈,奇异函数与Wythoff博弈,并查集,线段树,主席树,树状数组,ST表,LCA,BM算法,KMP,Trie树,AC自动机,匈牙利算法,KM算法,Floyd,dijkstra,dijkstra+heap优化,SPFA及LLL与SLF优化,Dinic,MCMF,Kruscal,Prim等等。

数据结构

基础

并查集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int fa[maxn];
void init(){
for(int i = 0; i < maxn; i++){
fa[i] = i;
}
}
int root(int x){
return x==fa[x] ? x : x=root(fa[x]);
}
void Union(int px, int py){
px = root(px);
py = root(py);
if(px != py){
fa[py] = px;
}
}

并查集路径压缩按雉合并

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include<bits/stdc++.h>
using namespace std;

const int maxn=1e5+7;
int fa[maxn],r[maxn];
int a[maxn];
int n,m;

void init(){
for(int i=0;i<=n;i++){
fa[i]=i;
r[i]=1;
}
}

int Find(int x){
return x==fa[x]?x:Find(fa[x]);
}

void Merge(int x,int y)
{
int t1=Find(x),t2=Find(y);
if(t1==t2) return ;//已合并返回
if(r[t1]>r[t2]) fa[t2]=t1; //把y的祖先t2和并到x的祖先t1上。因以t1为根的树更高
else {
fa[t1]=t2;
if(r[t1]==r[t2]) r[t2]++; //若两树一样高,那么合并后,高度加一。
}
}
int sum[maxn];
int main(){
cin>>n;
init();
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++)
cin>>a[i];
cin>>m;
while(m--){
int flag,x,y,z;
cin>>flag;
if(flag==1){
cin>>x>>y>>z;
int cnt=0;
for(int j=y+1;j<=z;j++){
Merge(j,j-1);
cnt+=a[j];
}
Merge(x,y);
cnt+=a[y];
sum[fa[x]]+=cnt;
}
else{
cin>>x>>y;
sum[fa[x]]=sum[fa[x]]-a[x]+y;
}
}
int minn=0x3f3f3f3f;
for(int i=1;i<=n;i++){
if(fa[i]==i){
minn=min(minn,sum[fa[i]]);
}
}
cout<<minn<<endl;


return 0;
}

加权并查集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<iostream>
#include<cstring>
using namespace std;
const int N = 2e5+5;
int n,m,s[N],p[N],ans;

void init(){
ans=0;
memset(s,0,sizeof(s));
for(int i=0;i<N;i++)
p[i]=i;
}

int fd(int x) { ///此时find不单有查找任务,还有更新距离任务
if(x==p[x]) return x;
int t=p[x];
p[x]=fd(p[x]);
s[x]+=s[t]; ///记录到根节点的距离,一定要有一个思想,根节点是一个区间的一个端点而不是一个区间,输入的区间被合并成了两个点
return p[x];
}

void Union(int a,int b,int num) {
int x=fd(a),y=fd(b);
if(x==y) {
if(s[b]!=s[a]+num) ans++;
}else {
p[y]=x;
s[y]=s[a]+num-s[b]; ///y到x的距离等于a到x的距离+b到a的距离-b到y的距离
}
}

int main(){
while(cin>>n>>m) {
init();
for(int i=0;i<m;i++) {
int a,b,c;
cin>>a>>b>>c;
Union(a-1,b,c);
///等价于Union(a,b+1,c);
}
cout<<ans<<endl;
}
}

单调队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>

using namespace std;
const int maxn=1e6+7;
int a[maxn];
int maxq[maxn];
int minq[maxn];
int q[maxn];
int n,k;

int main(){
ios::sync_with_stdio(false);
cin.tie(0);
while(cin>>n>>k){
for(int i=1;i<=n;i++)
cin>>a[i];
int head,tail,t;
memset(q,0,sizeof(q));
head=1,tail=1;
q[tail]=1;
minq[1]=a[1];
for(int i=2;i<=n;i++){
while(head<=tail&&a[i]<a[q[tail]])
tail--;
q[++tail]=i;
if(head<=tail&&q[head]<i-k+1)
head++;
minq[i]=a[q[head]];
}
memset(q,0,sizeof(q));
head=1,tail=1;
q[tail]=1;
maxq[1]=a[1];
for(int i=2;i<=n;i++){
while(head<=tail&&a[i]>a[q[tail]])
tail--;
q[++tail]=i;
if(head<=tail&&q[head]<i-k+1)
head++;
maxq[i]=a[q[head]];
}
for(int i=k;i<n;i++)
cout<<minq[i]<<" ";
cout<<minq[n]<<endl;
for(int i=k;i<n;i++)
cout<<maxq[i]<<" ";
cout<<maxq[n]<<endl;
}
return 0;
}

链式前向星

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int head[maxn], cnt;
struct EDGE{
int next, to, u, w;
}edge[maxm];
void add(int u, int v, int w){
edge[cnt].next = head[u];
edge[cnt].u = u;
edge[cnt].to = v;
edge[cnt].w = w;
head[u] = cnt++;
}
void init(){
cnt = 0;
memset(head, -1, sizeof(head));
//memset(edge, 0, sizeof(edge));
}

树结构

树状数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include<iostream>
using namespace std;
int n,m,i,num[100001],t[200001],l,r;//num:原数组;t:树状数组
int lowbit(int x)
{
return x&(-x);
}
void change(int x,int p)//将第x个数加p
{
while(x<=n)
{
t[x]+=p;
x+=lowbit(x);
}
return;
}
int sum(int k)//前k个数的和
{
int ans=0;
while(k>0)
{
ans+=t[k];
k-=lowbit(k);
}
return ans;
}
int ask(int l,int r)//求l-r区间和
{
return sum(r)-sum(l-1);
}
int main()
{
cin>>n>>m;
for(i=1;i<=n;i++)
{
cin>>num[i];
change(i,num[i]);
}
for(i=1;i<=m;i++)
{
cin>>l>>r;
cout<<ask(l,r)<<endl;
}
return 0;
}

线段树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include<bits/stdc++.h>
#define MAXN 100010
#define inf 0x3f3f3f3f

using namespace std;

struct node{
int l,r;//区间[l,r]
int add;//区间的延时标记
int sum;//区间和
int mx; //区间最大值
int mn; //区间最小值
}tree[MAXN<<2];//一定要开到4倍多的空间

void pushup(int index){
tree[index].sum = tree[index<<1].sum+tree[index<<1|1].sum;
tree[index].mx = max(tree[index<<1].mx,tree[index<<1|1].mx);
tree[index].mn = min(tree[index<<1].mn,tree[index<<1|1].mn);
}
void pushdown(int index){
//说明该区间之前更新过
//要想更新该区间下面的子区间,就要把上次更新该区间的值向下更新
if(tree[index].add){
//替换原来的值
/*
tree[index<<1].sum = (tree[index<<1].r-tree[index<<1].l+1)*tree[index].add;
tree[index<<1|1].sum = (tree[index<<1|1].r-tree[index<<1|1].l+1)*tree[index].add;
tree[index<<1].mx = tree[index].add;
tree[index<<1|1].mx = tree[index].add;
tree[index<<1].mn = tree[index].add;
tree[index<<1|1].mn = tree[index].add;
tree[index<<1].add = tree[index].add;
tree[index<<1|1].add = tree[index].add;
tree[index].add = 0;*/
//在原来的值的基础上加上val

tree[index<<1].sum += (tree[index<<1].r-tree[index<<1].l+1)*tree[index].add;
tree[index<<1|1].sum +=(tree[index<<1|1].r-tree[index<<1|1].l+1)*tree[index].add;
tree[index<<1].mx += tree[index].add;
tree[index<<1|1].mx += tree[index].add;
tree[index<<1].mn += tree[index].add;
tree[index<<1|1].mn += tree[index].add;
tree[index<<1].add += tree[index].add;
tree[index<<1|1].add += tree[index].add;
tree[index].add = 0;

}
}
void build(int l,int r,int index){
tree[index].l = l;
tree[index].r = r;
tree[index].add = 0;//刚开始一定要清0
if(l == r){
scanf("%d",&tree[index].sum);
tree[index].mn = tree[index].mx = tree[index].sum;
return ;
}
int mid = (l+r)>>1;
build(l,mid,index<<1);
build(mid+1,r,index<<1|1);
pushup(index);
}
void updata(int l,int r,int index,int val){
if(l <= tree[index].l && r >= tree[index].r){
/*把原来的值替换成val,因为该区间有tree[index].r-tree[index].l+1
个数,所以区间和 以及 最值为:
*/
/*tree[index].sum = (tree[index].r-tree[index].l+1)*val;
tree[index].mn = val;
tree[index].mx = val;
tree[index].add = val;//延时标记*/
//在原来的值的基础上加上val,因为该区间有tree[index].r-tree[index].l+1
//个数,所以区间和 以及 最值为:
tree[index].sum += (tree[index].r-tree[index].l+1)*val;
tree[index].mn += val;
tree[index].mx += val;
tree[index].add += val;//延时标记

return ;
}
pushdown(index);
int mid = (tree[index].l+tree[index].r)>>1;
if(l <= mid){
updata(l,r,index<<1,val);
}
if(r > mid){
updata(l,r,index<<1|1,val);
}
pushup(index);
}
int query(int l,int r,int index){
if(l <= tree[index].l && r >= tree[index].r){
//return tree[index].sum;
return tree[index].mx;
//return tree[index].mn;
}
pushdown(index);
int mid = (tree[index].l+tree[index].r)>>1;
int ans = 0;
int Max = 0;
int Min = inf;
if(l <= mid){
ans += query(l,r,index<<1);
Max = max(query(l,r,index<<1),Max);
Min = min(query(l,r,index<<1),Min);
}
if(r > mid){
ans += query(l,r,index<<1|1);
Max = max(query(l,r,index<<1|1),Max);
Min = min(query(l,r,index<<1|1),Min);
}
//return ans;
return Max;
//return Min;
}
int main()
{
int n,m,q,x,y,z;
while(~scanf("%d%d",&n,&m)){
build(1,n,1);
while(m--){
scanf("%d",&q);
if(q == 1){
cout<<"查询:(x,y)"<<endl;
scanf("%d %d",&x,&y);
cout<<query(x,y,1)<<endl;
}
else{
cout<<"更新(x,y)为z:"<<endl;
scanf("%d %d %d",&x,&y,&z);
updata(x,y,1,z);
for(int i = 1; i <= n; ++i){
printf("a[%d] = %d\n",i,query(i,i,1));
}
}
}
}
return 0;
}

主席树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[100010],hash[101000],tot,root[201000],cnt,n,m,tt,qll[200100],qrr[20000];
int q1,q2,id[201000],b[201000];
struct TREE
{
int ln,rn,zhi;
}t[10010000];
struct NODE
{
int l,r,k,flag;
}q[100100];
int lowbit(int x) {return (x)&(-x);}
void gai(int &node,int l,int r,int hs,int v)
{
if(!node) node=++tot;
t[node].zhi+=v;
if(l==r) return;
int mid=(l+r)/2;
if(hs<=mid) gai(t[node].ln,l,mid,hs,v);
else gai(t[node].rn,mid+1,r,hs,v);
}
void add(int p,int v)
{
hash[p]=lower_bound(a+1,a+1+tt,hash[p])-a;
//cout<<hash[p]<<endl;
for(int i=p;i<=n;i+=lowbit(i)) gai(root[i],1,tt,hash[p],v);
}
char s[2];
int SUM()
{
int ans1=0,ans2=0;
for(int i=1;i<=q1;i++) ans1+=t[t[qrr[i]].ln].zhi;
for(int i=1;i<=q2;i++) ans2+=t[t[qll[i]].ln].zhi;
return ans1-ans2;

}
int cha(int qr,int ql,int l,int r,int k)
{
q1=0,q2=0;
for(int i=qr;i>=1;i-=lowbit(i)) qrr[++q1]=root[i];
for(int i=ql;i>=1;i-=lowbit(i)) qll[++q2]=root[i];
while(l<r)
{
int lsiz=SUM(),mid=(l+r)/2;
if(k<=lsiz)
{
for(int i=1;i<=q1;i++) qrr[i]=t[qrr[i]].ln;
for(int i=1;i<=q2;i++) qll[i]=t[qll[i]].ln;
r=mid;
}
else
{
for(int i=1;i<=q1;i++) qrr[i]=t[qrr[i]].rn;
for(int i=1;i<=q2;i++) qll[i]=t[qll[i]].rn;
l=mid+1;k-=lsiz;
}
}
return l;
}
int main()
{
int x,y,z;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);b[i]=a[i];
hash[++cnt]=a[i];
}
for(int i=1;i<=m;i++)
{
scanf("%s",s);
if(s[0]=='Q')
scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k),q[i].flag=1;
else
{
scanf("%d%d",&q[i].l,&q[i].r);
a[++cnt]=q[i].r;hash[cnt]=a[cnt];
}
}
sort(a+1,a+1+cnt);
tt=unique(a+1,a+1+cnt)-a-1;
for(int i=1;i<=n;i++)
add(i,1);
for(int i=1;i<=m;i++)
{
if(q[i].flag==1)
printf("%d\n",a[cha(q[i].r,q[i].l-1,1,tt,q[i].k)]);
else
{
hash[q[i].l]=b[q[i].l];
add(q[i].l,-1);
hash[q[i].l]=q[i].r;
b[q[i].l]=q[i].r;
add(q[i].l,1);
}
}
}

划分树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/** 划分树(查询区间第 k 大)*/
const int MAXN = 100010;
int tree[20][MAXN];//表示每层每个位置的值
int sorted[MAXN];//已经排序好的数
int toleft[20][MAXN];//toleft[p][i] 表示第 i 层从 1 到 i 有数分入左边
void build(int l,int r,int dep)
{
if(l == r)
return;
int mid = (l+r)>>1;
int same = mid − l + 1;//表示等于中间值而且被分入左边的个数
for(int i = l; i <= r; i++) //注意是 l, 不是 one
if(tree[dep][i] < sorted[mid])
same−−;
int lpos = l;
int rpos = mid+1;
for(int i = l; i <= r; i++)
{
if(tree[dep][i] < sorted[mid])
tree[dep+1][lpos++] = tree[dep][i];
else if(tree[dep][i] == sorted[mid] && same > 0)
{
tree[dep+1][lpos++] = tree[dep][i];
same−−;
}
elsetree[dep+1][rpos++] = tree[dep][i];
toleft[dep][i] = toleft[dep][l−1] + lpos − l
}
build(l,mid,dep+1);
build(mid+1,r,dep+1);
}
//查询区间第 k 大的数,[L,R] 是大区间,[l,r] 是要查询的小区间
int query(int L,int R,int l,int r,int dep,int k)
{
if(l == r)
return tree[dep][l];
int mid = (L+R)>>1;
int cnt = toleft[dep][r] − toleft[dep][l−1];
if(cnt >= k)
{
int newl = L + toleft[dep][l−1] − toleft[dep][L−1];
int newr = newl + cnt − 1;
return query(L,mid,newl,newr,dep+1,k);
}
else
{
int newr = r + toleft[dep][R] − toleft[dep][r];
int newl = newr − (r−l−cnt);
return query(mid+1,R,newl,newr,dep+1,k−cnt)
}
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==2)
{
memset(tree,0,sizeof(tree));
for(int i = 1; i <= n; i++)
{
scanf("%d",&tree[0][i]);
sorted[i] = tree[0][i];
}
sort(sorted+1,sorted+n+1);
build(1,n,0);
int s,t,k;
while(m−−)
{
scanf("%d%d%d",&s,&t,&k);
printf("%d\n",query(1,n,s,t,0,k));
}
}
return 0
}

Trie树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e5+7;
char s[maxn];
int n,m;
bool p;
struct node
{
int count;
node * next[26];
}*root;
node * build()
{
node * k=new(node);
k->count=0;
memset(k->next,0,sizeof(k->next));
return k;
}
void insert()
{
node * r=root;
char * word=s;
while(*word)
{
int id=*word-'a';
if(r->next[id]==NULL) r->next[id]=build();
r=r->next[id];
r->count++;
word++;
}
}
int search()
{
node * r=root;
char * word=s;
while(*word)
{
int id=*word-'a';
r=r->next[id];
if(r==NULL) return 0;
word++;
}
return r->count;
}

int main(){
char str[11];
int i,j;
root=(struct dictree*)malloc(sizeof(struct dictree));
for(i=0;i<26;i++)
root->child[i]=0;
root->n=2;
while(gets(str),strcmp(str,"")!=0){
insert(str);
}
while(scanf("%s",str)!=EOF){
printf("%d\n",find(str));
}

}

伸展树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
 /*
An implementation of top-down splaying
D. Sleator <sleator@cs.cmu.edu>
March 1992
*/
#include <stdlib.h>
#include <stdio.h>
int size; /* number of nodes in the tree */
/* Not actually needed for any of the operations */
typedef struct tree_node Tree;
struct tree_node
{
Tree * left, * right;
int item;
};

Tree * splay (int i, Tree * t)
{
/* Simple top down splay, not requiring i to be in the tree t. */
/* What it does is described above. */
Tree N, *l, *r, *y;
if (t == NULL)
return t;
N.left = N.right = NULL;
l = r = &N;
for (;;)
{
if (i < t->item)
{
if (t->left == NULL)
{
break;
}
if (i < t->left->item)
{
y = t->left; /* rotate right */
t->left = y->right;
y->right = t;
t = y;
if (t->left == NULL)
{
break;
}
}
r->left = t; /* link right */
r = t;
t = t->left;
}
else if (i > t->item)
{
if (t->right == NULL)
{
break;
}
if (i > t->right->item)
{
y = t->right; /* rotate left */
t->right = y->left;
y->left = t;
t = y;
if (t->right == NULL)
{
break;
}
}
l->right = t; /* link left */
l = t;
t = t->right;
}
else
{
break;
}
}
l->right = t->left; /* assemble */
r->left = t->right;
t->left = N.right;
t->right = N.left;
return t;
}
/* Here is how sedgewick would have written this. */
/* It does the same thing. */
Tree * sedgewickized_splay (int i, Tree * t)
{
Tree N, *l, *r, *y;
if (t == NULL)
{
return t;
}
N.left = N.right = NULL;
l = r = &N;
for (;;)
{
if (i < t->item)
{
if (t->left != NULL && i < t->left->item)
{
y = t->left;
t->left = y->right;
y->right = t;
t = y;
}
if (t->left == NULL)
{
break;
}
r->left = t;
r = t;
t = t->left;
}
else if (i > t->item)
{
if (t->right != NULL && i > t->right->item)
{
y = t->right;
t->right = y->left;
y->left = t;
t = y;
}
if (t->right == NULL)
{
break;
}
l->right = t;
l = t;
t = t->right;
}
else
{
break;
}
}
l->right=t->left;
r->left=t->right;
t->left=N.right;
t->right=N.left;
return t;
}

Tree * insert(int i, Tree * t)
{
/* Insert i into the tree t, unless it's already there. */
/* Return a pointer to the resulting tree. */
Tree * new;

new = (Tree *) malloc (sizeof (Tree));
if (new == NULL)
{
printf("Ran out of space\n");
exit(1);
}
new->item = i;
if (t == NULL)
{
new->left = new->right = NULL;
size = 1;
return new;
}
t = splay(i,t);
if (i < t->item)
{
new->left = t->left;
new->right = t;
t->left = NULL;
size ++;
return new;
}
else if (i > t->item)
{
new->right = t->right;
new->left = t;
t->right = NULL;
size++;
return new;
}
else
{
/* We get here if it's already in the tree */
/* Don't add it again */
free(new);
return t;
}
}

Tree * delete(int i, Tree * t)
{
/* Deletes i from the tree if it's there. */
/* Return a pointer to the resulting tree. */
Tree * x;
if (t==NULL)
{
return NULL;
}
t = splay(i,t);
if (i == t->item)
{ /* found it */
if (t->left == NULL)
{
x = t->right;
}
else
{
x = splay(i, t->left);
x->right = t->right;
}
size--;
free(t);
return x;
}
return t; /* It wasn't there */
}

int main(int argv, char *argc[])
{
/* A sample use of these functions. Start with the empty tree, */
/* insert some stuff into it, and then delete it */
Tree * root;
int i;
root = NULL; /* the empty tree */
size = 0;
for (i = 0; i < 1024; i++)
{
root = insert((541*i) & (1023), root);
}
printf("size = %d\n", size);
for (i = 0; i < 1024; i++)
{
root = delete((541*i) & (1023), root);
}
printf("size = %d\n", size);
}

LCA(Tarjan)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e4 + 7;
const int inf = 0x3f3f3f3f;
int n, head[maxn], fa[maxn], head_2[maxn], cnt, cnt_2, sx;
bool vis[maxn];
struct EDGE{
int next, to, u;
}edge[maxn];
struct QUERY{
int next, to, u, lca;
}query[maxn];
void add_edge(int u, int v){
edge[cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].u = u;
head[u] = cnt++;
}
void add_query(int u, int v){
query[cnt_2].next = head_2[u];
query[cnt_2].to = v;
query[cnt_2].u = u;
head_2[u] = cnt_2++;
query[cnt_2].next = head_2[v];
query[cnt_2].to = u;
query[cnt_2].u = v;
head_2[v] = cnt_2++;
}
void init_edge(){
memset(head, -1, sizeof(head));
cnt = 0;
}
void init_query(){
memset(head_2, -1, sizeof(head_2));
cnt_2 = 0;
}
int root(int x){
return x = x == fa[x] ? x : root(fa[x]);
}
void tarjan(int x) {
fa[x] = x;
for (int i = head[x]; i != -1; i = edge[i].next) {
int v = edge[i].to;
tarjan(v);
fa[root(v)] = x;
}
vis[x] = true;
for (int i = head_2[x]; i != -1; i = query[i].next) {
int v = query[i].to;
if (vis[v]) {
query[i].lca = query[i^1].lca = root(v);
}
}
}
void read(){
int u, v;
scanf("%d", &n);
memset(vis, false, sizeof(vis));
for(int i = 1; i < n; i++){
scanf("%d%d", &u, &v);
add_edge(u, v);
vis[v] = true;
}
for(int i = 1; i<=n; i++){
if(!vis[i]){
sx = i;
break;
}
}
memset(vis, false, sizeof(vis));
scanf("%d%d", &u, &v);
add_query(u, v);
}
void solve(){
tarjan(sx);
for(int i = 0; i < cnt_2; i+=2){
printf("%d\n", query[i].lca);
}
}
int main(){
int T;
scanf("%d", &T);
while(T--){
init_edge();
init_query();
read();
solve();
}
return 0;
}
/*
2
16
1 14
8 5
10 16
5 9
4 6
8 4
4 10
1 13
6 15
10 11
6 7
10 2
16 3
8 1
16 12
16 7
5
2 3
3 4
3 1
1 5
3 5
*/
//4 3

RMQ

ST表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include<bits/stdc++.h>
using namespace std;

const int maxn=1e5+7;
int stmax[maxn][30];
int stmin[maxn][30];
int a[maxn];

void rmq_st(int n){
for(int i=1;i<=n;i++)
stmax[i][0]=stmin[i][0]=a[i];
int m=(int)(double(log(n))/log(2.0));
for(int j=1;j<=m;j++)
for(int i=1;i+(1<<j)-1<=n;i++){
stmax[i][j]=max(stmax[i][j-1],stmax[i+(1<<j-1)][j-1]);
stmin[i][j]=min(stmin[i][j-1],stmin[i+(1<<j-1)][j-1]);
}
}

void rmq_query(int l,int r){
int k=(int)((double)log(r-l+1)/log(2.0));
cout<<"Max is : "<<max(stmax[l][k],stmax[r-(1<<k)+1][k])<<endl;
cout<<"Min is : "<<min(stmin[l][k],stmin[r-(1<<k)+1][k])<<endl;
}

int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
rmq_st(n);
int l,r;
while(cin>>l>>r){
rmq_query(l,r);
}
return 0;
}

普通莫队

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/*	解释:
belong[x]x属于分块后的哪一块,Q[i]每个询问
modify(p,t)对p位置进行t修改,一般只有增加或者缩减这两种操作,具体问题具体分析
注意:
最后也可以不对询问id排序,直接保存到一个数组里面输出即可
*/
int a[nmax], belong[nmax];
ll ans = 0;
struct node {int l, r, id;ll ans;} Q[nmax];
bool cmp(node a, node b) {
if (belong[a.l] != belong[b.l]) return a.l < b.l;
else return a.r < b.r;
}
bool cmpid(node a, node b) {return a.id < b.id;}
void modify(int pos, int tag) {
// ......... 增删操作
}
int main() {
scanf("%d %d", &n, &m);
int sz = sqrt(n);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for (int i = 1; i <= m; ++i) {
scanf("%d %d", &Q[i].l, &Q[i].r), Q[i].id = i;
belong[i] = (i - 1) / sz + 1;
}
sort(Q + 1, Q + 1 + m, cmp);
int l = 1, r = 0;
for (int i = 1; i <= m; ++i) {
while (l < Q[i].l) modify(l++, -1);
while (l > Q[i].l) modify(--l, 1);
while (r > Q[i].r) modify(r--, -1);
while (r < Q[i].r) modify(++r, 1);
Q[i].ans = ans;
}
sort(Q + 1, Q + 1 + m, cmpid);
for (int i = 1; i <= m; ++i) printf("%I64d\n", Q[i].ans);
return 0;
}

莫队

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=3e5+5;//区间范围
const int MAX=1e6+5;//最大数字
int unit,cnt[MAX],arr[N],res[N],ans=0;

struct node{
int l,r,id;
}q[N];

bool cmp(node a,node b){
return a.l/unit!=b.l/unit?a.l/unit<b.l/unit:a.r<b.r;
}

void add(int pos){
cnt[arr[pos]]++;
if(cnt[arr[pos]]==1){
ans++;
}
}

void remove(int pos){
cnt[arr[pos]]--;
if(cnt[arr[pos]]==0){
ans--;
}
}

int main(){
int n;
scanf("%d",&n);
unit=sqrt(n);
for(int i=1;i<=n;i++){
scanf("%d",&arr[i]);
}
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}

sort(q+1,q+m+1,cmp);

int L=q[1].l,R=L-1;
for(int i=1;i<=m;i++){
while(L>q[i].l)
add(--L);
while(L<q[i].l)
remove(L++);
while(R>q[i].r)
remove(R--);
while(R<q[i].r)
add(++R);
res[q[i].id]=ans;
}
for(int i=1;i<=m;i++){
printf("%d\n",res[i]);
}
}

动态规划

背包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int nValue,nKind;
//0-1 背包,代价为 cost, 获得的价值为 weight
void ZeroOnePack(int cost,int weight)
{
for(int i=nValue; i>=cost; i−−)
dp[i]=max(dp[i],dp[i−cost]+weight);
}
//完全背包,代价为 cost, 获得的价值为 weight
void CompletePack(int cost,int weight)
{
for(int i=cost; i<=nValue; i++)
dp[i]=max(dp[i],dp[i−cost]+weight);
}
//多重背包
void MultiplePack(int cost,int weight,int amount)
{
if(cost*amount>=nValue)
CompletePack(cost,weight);
else
{
int k=1;
while(k<amount)
{
ZeroOnePack(k*cost,k*weight);
amount−=k;
k<<=1;
}
ZeroOnePack(amount*cost,amount*weight);//这个不要忘记了,经常掉了
}
}
//分组背包:
for k = 1 to K
for v = V to 0
for item i in group k
F[v] = maxF[v],F[v-Ci]+Wi

最长上升子序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const int MAXN=500010;
int a[MAXN],b[MAXN]//用二分查找的方法找到一个位置,使得 num>b[i-1] 并且 num<b[i], 并用 num 代替
b[i]int Search(int num,int low,int high)
{
int mid;
while(low<=high)
{
mid=(low+high)/2;
if(num>=b[mid])
low=mid+1;
else
high=mid−1;
}
return low;
}
int DP(int n)
{
int i,len,pos;
b[1]=a[1];
len=1;
for(i=2; i<=n; i++)
{
if(a[i]>=b[len])//如果 a[i] 比 b[] 数组中最大还大直接插入到后面即可
{
len=len+1;
b[len]=a[i];
}
else //用二分的方法在 b[] 数组中找出第一个比 a[i] 大的位置并且让a[i] 替代这个位置
{
pos=Search(a[i],1,len);
b[pos]=a[i];
}
}
return len;
}

最长公共子序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;

const int MAXN = 1005;

int DP[MAXN][MAXN];

int main()
{
string a;
string b;
while(cin >> a >> b)
{
int l1 = a.size();
int l2 = b.size();
memset(DP, 0, sizeof(DP));
for(int i = 1; i <= l1; i++)
for(int j = 1; j <= l2; j++)
if(a[i - 1] == b[j - 1])
DP[i][j] = max(DP[i][j], DP[i - 1][j - 1] + 1);
else
DP[i][j] = max(DP[i][j - 1], DP[i - 1][j]);
printf("%d\n", DP[l1][l2]);
}
return 0;
}

概率dp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
POJ 2096

/*
POJ 2096
概率DP

dp求期望
逆着递推求解
题意:(题意看题目确实比较难道,n和s都要找半天才能找到)
一个软件有s个子系统,会产生n种bug
某人一天发现一个bug,这个bug属于一个子系统,属于一个分类
每个bug属于某个子系统的概率是1/s,属于某种分类的概率是1/n
问发现n种bug,每个子系统都发现bug的天数的期望。

求解:
dp[i][j]表示已经找到i种bug,j个系统的bug,达到目标状态的天数的期望
dp[n][s]=0;要求的答案是dp[0][0];
dp[i][j]可以转化成以下四种状态:
dp[i][j],发现一个bug属于已经有的i个分类和j个系统。概率为(i/n)*(j/s);
dp[i][j+1],发现一个bug属于已有的分类,不属于已有的系统.概率为 (i/n)*(1-j/s);
dp[i+1][j],发现一个bug属于已有的系统,不属于已有的分类,概率为 (1-i/n)*(j/s);
dp[i+1][j+1],发现一个bug不属于已有的系统,不属于已有的分类,概率为 (1-i/n)*(1-j/s);
整理便得到转移方程
*/
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int MAXN=1010;
double dp[MAXN][MAXN];

int main()
{
int n,s;
while(scanf("%d%d",&n,&s)!=EOF)
{
dp[n][s]=0;
for(int i=n;i>=0;i--)
for(int j=s;j>=0;j--)
{
if(i==n&&j==s)continue;
dp[i][j]=(i*(s-j)*dp[i][j+1]+(n-i)*j*dp[i+1][j]+(n-i)*(s-j)*dp[i+1][j+1]+n*s)/(n*s-i*j);
}
printf("%.4lf\n",dp[0][0]);//POJ上G++要改成%.4f
}
return 0;
}

轮廓线dp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/*
HDU 4285
要形成刚好 K 条回路的方法数要避免环套环的情况。
所以形成回路时,要保证两边的插头数是偶数
G++ 11265ms 11820K
C++ 10656ms 11764K
*/
const int MAXD=15;
const int STATE=1000010;
const int HASH=300007;//这个大一点可以防止 TLE, 但是容易 MLE
const int MOD=1000000007;
int N,M,K;
int maze[MAXD][MAXD];
int code[MAXD];
int ch[MAXD];
int num;//圈的个数
struct HASHMAP
{
int head[HASH],next[STATE],size;
long long state[STATE];
int f[STATE];
void init()
{
size=0;
memset(head,−1,sizeof(head));
} void push(long long st,int ans)
{
int i;
int h=st%HASH;
for(i=head[h]; i!=−1; i=next[i])
if(state[i]==st)
{
f[i]+=ans;
f[i]%=MOD;
return;
}
state[size]=st;
f[size]=ans;
next[size]=head[h];
head[h]=size++;
}
} hm[2];
void decode(int *code,int m,long long st)
{
num=st&63;
st>>=6;
for(int i=m; i>=0; i−−)
{
code[i]=st&7;
st>>=3;
}
}
long long encode(int *code,int m)//最小表示法
{
int cnt=1;
memset(ch,−1,sizeof(ch));
ch[0]=0;
long long st=0;
for(int i=0; i<=m; i++)
{
if(ch[code[i]]==−1)
ch[code[i]]=cnt++;
code[i]=ch[code[i]];
st<<=3;
st|=code[i];
}
st<<=6;
st|=num;
return st;
}
void shift(int *code,int m)
{
for(int i=m; i>0; i−−)
code[i]=code[i−1];
code[0]=0;
}
void dpblank(int i,int j,int cur)
{
int k,left,up;
for(k=0; k<hm[cur].size; k++)
{
decode(code,M,hm[cur].state[k]);
left=code[j−1];
up=code[j];
if(left&&up)
{
if(left==up)
{
if(num>=K)
continue;
int t=0;//要避免环套环的情况,需要两边插头数为偶数
for(int p=0; p<j−1; p++)
if(code[p])
t++;
if(t&1)
continue;
if(num<K)
{
num++;
code[j−1]=code[j]=0;
hm[cur^1].push(encode(code,j==M?M−1:M),hm[cur].f[k]);
}
}
else
{
code[j−1]=code[j]=0;
for(int t=0; t<=M; t++)
if(code[t]==up)
code[t]=left;
hm[cur^1].push(encode(code,j==M?M−1:M),hm[cur].f[k]);
}
}
else if(left||up)
{
int t;
if(left)
t=left;
else
t=up;
if(maze[i][j+1])
{
code[j−1]=0;
code[j]=t;
hm[cur^1].push(encode(code,M),hm[cur].f[k]);
}
if(maze[i+1][j])
{
code[j]=0;
code[j−1]=t;
hm[cur^1].push(encode(code,j==M?M−1:M),hm[cur].f[k]);
}
}
else
{
if(maze[i][j+1]&&maze[i+1][j])
{
code[j−1]=code[j]=13;
hm[cur^1].push(encode(code,j==M?M−1:M),hm[cur].f[k]);
}
}
}
}
void dpblock(int i,int j,int cur)
{
int k;
for(k=0; k<hm[cur].size; k++)
{
decode(code,M,hm[cur].state[k]);
code[j−1]=code[j]=0;
hm[cur^1].push(encode(code,j==M?M−1:M),hm[cur].f[k]);
}
}
char str[20];
void init()
{
scanf("%d%d%d",&N,&M,&K);
memset(maze,0,sizeof(maze));
for(int i=1; i<=N; i++)
{
scanf("%s",&str);
for(int j=1; j<=M; j++)
if(str[j−1]=='.')
maze[i][j]=1;
}
}
void solve()
{
int i,j,cur=0;
hm[cur].init();
hm[cur].push(0,1);
for(i=1; i<=N; i++)
for(j=1; j<=M; j++)
{
hm[cur^1].init();
if(maze[i][j])
dpblank(i,j,cur);
else
dpblock(i,j,cur);
cur^=1;
}
int ans=0;
for(i=0; i<hm[cur].size; i++)
if(hm[cur].state[i]==K)
{
ans+=hm[cur].f[i];
ans%=MOD;
}
printf("%d\n",ans);
}
int main()
{
int T;
scanf("%d",&T);
while(T−−)
{
init();
solve();
}
return 0;
}
/*
Sample Input
4 4 1
**..
....
....
....
4 1
....
....
....
....
Sample Output
6
*/

图论

最短路

Dijkstra(邻接矩阵)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 3007;
const int inf = 0x3f3f3f3f;
int road[maxn][maxn];
int dis[maxn];
bool vis[maxn];
int n, m, sx, ex;
void init(){
memset(road, inf, sizeof(road));
}
int dijkstra(int sx, int ex){
memset(vis, false, sizeof(vis));
memset(dis, inf, sizeof(dis));
dis[sx] = 0;
for(int u = 1; u<=n; u++){
int minD = inf, k = -1;
for(int i = 1; i<= n; i++){
if(!vis[i] && dis[i] < minD){
k = i;
minD = dis[i];
}
}
//if(k == ex)
// return dis[ex];
vis[k] = true;
for(int i = 1; i<= n; i++){
if(!vis[i] && dis[k] + road[k][i] < dis[i]){
dis[i] = dis[k] + road[k][i];
}
}
}
return dis[ex];
}
void read(){
int u, v, w;
sx = 1, ex = n;
for(int i = 0; i < m; i++){
scanf("%d%d%d", &u, &v, &w);
road[u][v] = min(road[u][v], w);
//road[v][u] = min(road[v][u], w); //双向边
}
}
void solve(){
printf("%d\n", dijkstra(sx, ex));
}
int main(){
while(~scanf("%d%d", &n, &m)){
init();
read();
solve();
}
return 0;
}

Dijkstra

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 3007;
const int inf = 0x3f3f3f3f;
struct EDGE{
int next, to, w;
}edge[maxn<<4];
int head[maxn], dis[maxn], cnt;
bool vis[maxn];
int n, m, sx, ex;
void add(int u, int v, int w){
edge[cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].w = w;
head[u] = cnt++;
}
void init(){
cnt = 0;
memset(head, -1, sizeof(head));
}
int dijkstra(int sx, int ex){
memset(vis, false, sizeof(vis));
memset(dis, inf, sizeof(dis));
dis[sx] = 0;
for(int cas = 1; cas<=n; cas++){
int minD = inf, kk = -1;
for(int i = 1; i<= n; i++){
if(!vis[i] && dis[i] < minD){
kk = i;
minD = dis[i];
}
}
//if(kk == ex)
// return dis[ex];
vis[kk] = true;
for(int i = head[kk]; i != -1; i = edge[i].next){
int v = edge[i].to;
if(!vis[v] && dis[kk] + edge[i].w < dis[v]){
dis[v] = dis[kk] + edge[i].w;
}
}
}
return dis[ex];
}
void read(){
int u, v, w;
sx = 1, ex = n;
for(int i = 0; i < m; i++){
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
//add(v, u, w); //双向边
}
}
void solve(){
printf("%d\n", dijkstra(sx, ex));
}
int main(){
while(~scanf("%d%d", &n, &m)){
init();
read();
solve();
}
return 0;
}

Dijkstra+heap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 3007;
const int inf = 0x3f3f3f3f;
struct EDGE{
int next, to, w;
}edge[maxn<<4];
int head[maxn], dis[maxn], cnt;
bool vis[maxn];
int n, m, sx, ex;
struct NODE{
int u;
int dis;
NODE(){}
NODE(int x, int y) : u(x), dis(y){}
bool operator <(const NODE &a)const{
return dis>a.dis;
}
};
void add(int u, int v, int w){
edge[cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].w = w;
head[u] = cnt++;
}
void init(){
cnt = 0;
memset(head, -1, sizeof(head));
}
int dijkstra(int sx, int ex){
memset(vis, false, sizeof(vis));
memset(dis, inf, sizeof(dis));
dis[sx] = 0;
priority_queue<NODE>que;
que.push(NODE(sx, 0));
while(!que.empty()){
NODE tmp = que.top();
que.pop();
int kk = tmp.u;
if(vis[kk]){
continue;
}
vis[kk] = true;
for(int i = head[kk]; i != -1; i = edge[i].next){
int v = edge[i].to;
if(!vis[v] && dis[kk] + edge[i].w < dis[v]){
dis[v] = dis[kk] + edge[i].w;
que.push(NODE(v, dis[v]));
}
}
}
return dis[ex];
}
void read(){
scanf("%d%d", &n, &m);
int u, v, w;
sx = 1, ex = n;
for(int i = 0; i < m; i++){
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
add(v, u, w); //双向边
}
}
void solve(){
printf("%d\n", dijkstra(sx, ex));
}
int main(){
int T;
while(T--){
init();
read();
solve();
}
return 0;
}

SPFA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1e3+7;
int n, m, sx, ex;
int head[maxn], dis[maxn], cnt;
bool vis[maxn];
struct EDGE{
int next, to, w, u;
}edge[maxn<<3];
void init(){
cnt = 0;
memset(head, -1, sizeof(head));
}
void add(int u, int v, int w){
edge[cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].u = u;
edge[cnt].w = w;
head[u] = cnt++;
}
int SPFA(int sx, int ex){
memset(vis, false, sizeof(vis));
memset(dis, inf, sizeof(dis));
queue<int>que;
dis[sx] = 0;
que.push(sx);
while(!que.empty()){
int kk = que.front();
que.pop();
vis[kk] = false;
for(int i = head[kk]; i != -1; i = edge[i].next){
int v = edge[i].to;
if(dis[v] > dis[kk] + edge[i].w){
dis[v] = dis[kk] + edge[i].w;
if(!vis[v]){
vis[v] = true;
que.push(v);
}
}
}
}
return dis[ex];
}
int main(){
while(~scanf("%d%d", &n, &m)){
init();
sx = 1, ex = n;
for(int i = 0; i < m; i++){
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
//add(v, u, w); //双向边
}
printf("%d\n", SPFA(sx, ex));
}
}

SPFA+SLF优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include<bits/stdc++.h>

using namespace std;

const int MAXN=1e2;

int phi[MAXN],n,tot;
int pri[MAXN];
bool mark[MAXN];

void getphi(){
phi[1]=1;
for(int i=2;i<=n;i++){
if(!mark[i]){
phi[i]=i-1;
pri[++tot]=i;
}
for(int j=1;j<=tot;j++){
int x=pri[j];
if(i*x>n) break;
mark[i*x]=1;
if(i%x==0){
phi[i*x]=phi[i]*x;
break;
}
else phi[i*x]=phi[i]*phi[x];
}
}
}

int main(){
while(~scanf("%d",&n)){
tot=0;
getphi();

printf("%d\n",phi[n]);
}
return 0;
}

Floyd

1
2
3
4
5
for(k=1; k<=n; k++)
for(i=1; i<=n; i++)
for(j=1; j<=n; j++)
if(e[i][j]>e[i][k]+e[k][j])
e[i][j]=e[i][k]+e[k][j];

K短路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/**
* poj
* Problem#2449
* Accepted
* Time: 438ms
* Memory: 15196k
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
typedef bool boolean;

#define pii pair<int, int>
#define fi first
#define sc second

typedef class Node {
public:
int val, ed;
Node *l, *r;

Node() { }
Node(int val, int ed, Node *l, Node *r):val(val), ed(ed), l(l), r(r) { }
}Node;

#define Limit 1000000

Node pool[Limit];
Node* top = pool;

Node* newnode(int val, int ed) {
if(top >= pool + Limit)
return new Node(val, ed, NULL, NULL);
top->val = val, top->ed = ed, top->l = top->r = NULL;
return top++;
}

Node* merge(Node* a, Node* b) {
if (!a) return b;
if (!b) return a;
if (a->val > b->val) swap(a, b);
Node* p = newnode(a->val, a->ed);
p->l = a->l, p->r = a->r;
p->r = merge(p->r, b);
swap(p->l, p->r);
return p;
}

typedef class Status {
public:
int dist;
Node* p;

Status(int dist = 0, Node* p = NULL):dist(dist), p(p) { }

boolean operator < (Status b) const {
return dist > b.dist;
}
}Status;

typedef class Edge {
public:
int end, next, w;

Edge(int end = 0, int next = 0, int w = 0):end(end), next(next), w(w) { }
}Edge;

typedef class MapManager {
public:
int ce;
int* h;
Edge* es;

MapManager() { }
MapManager(int n, int m):ce(0) {
h = new int[(n + 1)];
es = new Edge[(m + 5)];
memset(h, 0, sizeof(int) * (n + 1));
}

void addEdge(int u, int v, int w) {
es[++ce] = Edge(v, h[u], w);
h[u] = ce;
}

Edge& operator [] (int pos) {
return es[pos];
}
}MapManager;

int n, m;
int s, t, k;
MapManager g;
MapManager rg;
boolean *vis;
int* f, *lase;

inline void init() {
scanf("%d%d", &n, &m);
g = MapManager(n, m);
rg = MapManager(n, m);
for (int i = 1, u, v, w; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
g.addEdge(u, v, w);
rg.addEdge(v, u, w);
}
scanf("%d%d%d", &s, &t, &k);
}

queue<int> que;
void spfa(MapManager& g, int s) {
vis = new boolean[(n + 1)];
f = new int[(n + 1)];
lase = new int[(n + 1)];
memset(f, 0x7f, sizeof(int) * (n + 1));
memset(vis, false, sizeof(boolean) * (n + 1));
que.push(s);
f[s] = 0, lase[s] = 0;
while (!que.empty()) {
int e = que.front();
que.pop();
vis[e] = false;
for (int i = g.h[e]; i; i = g[i].next) {
int eu = g[i].end, w = g[i].w;
if (f[e] + w < f[eu]) {
f[eu] = f[e] + w, lase[eu] = i;
if (!vis[eu]) {
vis[eu] = true;
que.push(eu);
}
}
}
}
}

Node** hs;
inline void rebuild() {
for (int i = 1; i <= n; i++)
for (int j = g.h[i]; j; j = g[j].next) {
int e = g[j].end;
if (lase[i] != j)
g[j].w += f[e] - f[i];
}

hs = new Node*[(n + 1)];
que.push(t);
hs[t] = NULL;
while (!que.empty()) {
int e = que.front();
que.pop();
if (lase[e])
hs[e] = hs[g[lase[e]].end];
for (int i = g.h[e]; i; i = g[i].next)
if (lase[e] != i && f[g[i].end] != 0x7f7f7f7f)
hs[e] = merge(hs[e], new Node(g[i].w, g[i].end, NULL, NULL));
for (int i = rg.h[e]; i; i = rg[i].next) {
int eu = rg[i].end;
if (lase[eu] == i)
que.push(eu);
}
}
}

inline int kthpath(int k) {
if (s == t)
k++;
if (f[s] == 0x7f7f7f7f)
return -1;
if (k == 1)
return f[s];

priority_queue<Status> q;
if (!hs[s])
return -1;

q.push(Status(hs[s]->val, hs[s]));
while (--k && !q.empty()) {
Status e = q.top();
q.pop();

if(k == 1)
return e.dist + f[s];

int eu = e.p->ed;
if (hs[eu])
q.push(Status(e.dist + hs[eu]->val, hs[eu]));
if (e.p->l)
q.push(Status(e.dist - e.p->val + e.p->l->val, e.p->l));
if (e.p->r)
q.push(Status(e.dist - e.p->val + e.p->r->val, e.p->r));
}
return -1;
}

inline void solve() {
printf("%d\n", kthpath(k));
}

int main() {
init();
spfa(rg, t);
rebuild();
solve();
return 0;
}
//最短路算法+可持久化堆

生成树

Kruskal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

//并查集实现最小生成树
vector<int> u, v, weights, w_r, father;
int mycmp(int i, int j)
{
return weights[i] < weights[j];
}
int find(int x)
{
return father[x] == x ? x : father[x] = find(father[x]);
}
void kruskal_test()
{
int n;
cin >> n;
vector<vector<int> > A(n, vector<int>(n));
for(int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cin >> A[i][j];
}
}

int edges = 0;
// 共计n*(n - 1)/2条边
for (int i = 0; i < n - 1; ++i) {
for (int j = i + 1; j < n; ++j) {
u.push_back(i);
v.push_back(j);
weights.push_back(A[i][j]);
w_r.push_back(edges++);
}
}
for (int i = 0; i < n; ++i) {
father.push_back(i); // 记录n个节点的根节点,初始化为各自本身
}

sort(w_r.begin(), w_r.end(), mycmp); //以weight的大小来对索引值进行排序

int min_tree = 0, cnt = 0;
for (int i = 0; i < edges; ++i) {
int e = w_r[i]; //e代表排序后的权值的索引
int x = find(u[e]), y = find(v[e]);
//x不等于y表示u[e]和v[e]两个节点没有公共根节点,可以合并
if (x != y) {
min_tree += weights[e];
father[x] = y;
++cnt;
}
}
if (cnt < n - 1) min_tree = 0;
cout << min_tree << endl;
}

int main(void)
{

kruskal_test();

return 0;
}

Prim

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <iostream>
#include <vector>
using namespace std;

//Prim算法实现
void prim_test()
{
int n;
cin >> n;
vector<vector<int> > A(n, vector<int>(n));
for(int i = 0; i < n ; ++i) {
for(int j = 0; j < n; ++j) {
cin >> A[i][j];
}
}

int pos, minimum;
int min_tree = 0;
//lowcost数组记录每2个点间最小权值,visited数组标记某点是否已访问
vector<int> visited, lowcost;
for (int i = 0; i < n; ++i) {
visited.push_back(0); //初始化为0,表示都没加入
}
visited[0] = 1; //最小生成树从第一个顶点开始
for (int i = 0; i < n; ++i) {
lowcost.push_back(A[0][i]); //权值初始化为0
}

for (int i = 0; i < n; ++i) { //枚举n个顶点
minimum = max_int;
for (int j = 0; j < n; ++j) { //找到最小权边对应顶点
if(!visited[j] && minimum > lowcost[j]) {
minimum = lowcost[j];
pos = j;
}
}
if (minimum == max_int) //如果min = max_int表示已经不再有点可以加入最小生成树中
break;
min_tree += minimum;
visited[pos] = 1; //加入最小生成树中
for (int j = 0; j < n; ++j) {
if(!visited[j] && lowcost[j] > A[pos][j]) lowcost[j] = A[pos][j]; //更新可更新边的权值
}
}

cout << min_tree << endl;
}

int main(void)
{
prim_test();

return 0;
}

次小生成树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cstdio>
#include <string>

using namespace std;
typedef long long LL;

const int MAXN = 500;
const int MAXE = 500 * 500;
const int INF = 0x3f3f3f3f;
int pre[MAXN + 7];

void initPre(int n){ for(int i = 0; i <= n; i++) pre[i] = i; }

//并查集
int Find(int x){ return x == pre[x] ? x : pre[x] = Find(pre[x]); }

void merge(int x, int y){ int fx = Find(x), fy = Find(y); if(fx != fy) pre[fx] = fy; }

struct Edge{ //前向星存边
int u, v; //起点 终点
int w;
bool select;
}edge[MAXE + 7];

bool cmp(Edge a, Edge b){
if(a.w != b.w) return a.w < b.w;
if(a.u != b.u) return a.u < b.u;
return a.v < b.v;
}

struct Node{//链式前向星 用于存储每个集合里面的边
int to;
int next;
}link[MAXN + 7];

int head[MAXN + 7];//邻接表的头结点的位置
int End[MAXN + 7];//邻接表的尾节点的位置
int length[MAXN + 7][MAXN + 7];//最小生成树中任意两点路径上的最长边

int kruskal(int n, int m){
//初始化邻接表,对于每一个顶点添加一个指向自身的边,表示以i为代表元的集合中只有点i
for(int i = 1; i <= n; i++){
link[i].to = i, link[i].next = head[i];
End[i] = i, head[i] = i;
}
sort(edge + 1, edge + 1 + m, cmp);
int cnt = 0;
for(int i = 1; i <= m; i++){
if(cnt == n - 1) break;//当找到的边数等于节点数-1,说明mst已经找到
int fx = Find(edge[i].u);
int fy = Find(edge[i].v);
if(fx != fy){
for(int j = head[fx]; j != -1; j = link[j].next)//修改length数组
for(int k = head[fy]; k != -1; k = link[k].next)
//每次合并两个等价类的之后,分别属于两个等价类的两个节点之间的最长边一定是当前加入的边
length[link[j].to][link[k].to] = length[link[k].to][link[j].to] = edge[i].w;
//合并邻接表
link[End[fy]].next = head[fx];
End[fy] = End[fx];
merge(fx, fy);
cnt++;
edge[i].select = true;
}
}
if(cnt < n - 1) return -1;
return 1;
}

int main(){
//初始化建图后执行以下操作
int flag = kruskal(n, m);
int mst = 0;
for(int i = 1; i <= m; i++) if(edge[i].select) mst += edge[i].w;//计算出最小生成树
int secmst = INF;
//在 T/(u,v) + (x, y)中寻得次小生成树
for(int i = 1; i <= m; i++) if(!edge[i].select) secmst = min(secmst, mst + edge[i].w - length[edge[i].u][edge[i].v]);
return 0;
}

拓扑排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*hdu1285--采用二维数组记录两者之间的关系*/
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
int map[510][510];//前驱数量
int indegree[510];
int queue[510];//保存拓扑序列
void topo(int n)
{
int i,j,m,t=0;
for(j=1;j<=n;j++){
for(i=1;i<=n;i++){
if(indegree[i]==0){//找出前驱数量为零的的点即每次找到第一名
m=i;break;
}
}
queue[t++]=m;indegree[m]=-1;//将第一名的前驱数量设为-1
for(i=1;i<=n;++i){//第二步将前驱中含有第一名的点前驱数量减1
if(map[m][i])indegree[i]--;
}
}
printf("%d",queue[0]);//输出拓扑序列
for(i=1;i<n;++i){
printf(" %d",queue[i]);
}
printf("\n");
}
int main()
{
int n,m,i,j,a,b;
while(scanf("%d%d",&n,&m)!=EOF){
memset(indegree,0,sizeof(indegree));//初始化
memset(map,0,sizeof(map));
for(i=0;i<m;++i){
scanf("%d%d",&a,&b);
if(map[a][b]==0){ //避免重复的数据输入
map[a][b]=1;indegree[b]++;//第一步记录关系和点的前驱数量
}
}
topo(n);//调用拓扑排序
}
return 0;
}

网络流

FF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include<bits/stdc++.h>
#include<vector>
#define maxn 1200
#define INF 2e9
using namespace std;
int i,j,k,n,m,h,t,tot,ans,st,en;
struct node{
int c,f;
}edge[maxn][maxn];
int flag[maxn],pre[maxn],alpha[maxn],q[maxn],v;
int read(){
char c;int x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}

void bfs(){
memset(flag,0xff,sizeof(flag));memset(pre,0xff,sizeof(pre));memset(alpha,0xff,sizeof(alpha));
flag[st]=0;pre[st]=0;alpha[st]=INF;h=0,t=1;q[t]=st;
while(h<t){
h++;v=q[h];
for(int i=1;i<=n;i++){
if(flag[i]==-1){
if(edge[v][i].c<INF&&edge[v][i].f<edge[v][i].c){
flag[i]=0;pre[i]=v;alpha[i]=min(alpha[v],edge[v][i].c-edge[v][i].f);q[++t]=i;
}
else if(edge[i][v].c<INF&&edge[i][v].f>0){
flag[i]=0;pre[i]=-v;alpha[i]=min(alpha[v],edge[i][v].f);q[++t]=i;
}
}
}
flag[v]=1;
}
}

void Ford_Fulkerson(){
while(1){
bfs();
if(alpha[en]==0||flag[en]==-1){
break;
}
int k1=en,k2=abs(pre[k1]);int a=alpha[en];
while(1){
if(edge[k2][k1].c<INF) edge[k2][k1].f+=a;
else if(edge[k1][k2].c<INF) edge[k1][k2].f-=a;
if(k2==st) break;
k1=k2;k2=abs(pre[k1]);
}
alpha[en]=0;
}
}

void flow(){
int maxflow=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
if(i==st&&edge[i][j].f<INF) maxflow+=edge[i][j].f;
}
printf("%d",maxflow);
}

int main(){
int u,v,c,f;
n=read();m=read();st=read();en=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) edge[i][j].c=INF,edge[i][j].f=0;
for(int i=1;i<=m;i++){
u=read();v=read();c=read();
edge[u][v].c=c;
}
Ford_Fulkerson();
flow();
return 0;
}

EK

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <bits/stdc++.h> 
using namespace std;
#define INF 0x3f3f3f
#define maxn 10005

int n, m, st, en, flow[maxn][maxn], pre[maxn];
int q[maxn], curr_pos, st_pos, end_pos;
bool wh[maxn];
int max_flow;

void Init()//初始化
{
int i, a, b, c;
scanf("%d%d%d%d", &n, &m, &st, &en);
for(i = 0; i != m; ++i)
{
scanf("%d%d%d", &a, &b, &c);
flow[a][b] += c;
}
return ;
}

bool Bfs(int st, int en)//广搜找源点
{
st_pos = -1, end_pos = 0;
memset(wh, 0, sizeof wh);
wh[st] = 1;
q[0] = st;
while(st_pos != end_pos)
{
curr_pos = q[++st_pos];
for(int i = 1; i != n+1; ++i)
{
if(!wh[i] && flow[curr_pos][i] > 0)
{
wh[i] = 1;
pre[i] = curr_pos;
if(i == en)
{
return true;
}
q[++end_pos] = i;
}
}
}
return false;
}

int EK(int start_pos, int end_pos)
{
int i, minn;
while(Bfs(start_pos, end_pos))//回溯
{
minn = INF;

for(i = end_pos; i != start_pos; i = pre[i])
{
minn = min(minn, flow[pre[i]][i]);
}

for(i = end_pos; i != start_pos; i = pre[i])
{
flow[pre[i]][i] -= minn;
flow[i][pre[i]] += minn;//反向弧加上该值(具体原因下文详解)
}
max_flow += minn;
}
return max_flow;
}

int main()
{
//freopen("test.in", "r", stdin);
//freopen("test.out", "w", stdout);

Init();

printf("%d", EK(st, en));

//fclose(stdin);
//fclose(stdout);
}

DINIC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e5+7;
const int inf = 0x3f3f3f3f;
int n, m, sx, ex, cnt;
int head[maxn], pre[maxn];
struct EDGE{
int u, next, to, c;
}edge[maxn<<3];
void add_edge(int u, int v, int c){
edge[cnt].u = u;
edge[cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].c = c<=inf ? c : inf;
head[u] = cnt++;
}
void add(int u, int v, int c){
add_edge(u, v, c);
add_edge(v, u, 0);//双向边容量为c
}
void init(){
//memset(edge, 0, sizeof(edge));
memset(head, -1, sizeof(head));
cnt = 0;
}
void read(){
sx = 1, ex = n;
for(int i = 0; i < m; i++){
int u, v, w;
scanf("%d%d%d",&u, &v, &w);
add(u, v, w);
}
}
bool BFS(int sx, int ex){
memset(pre, 0, sizeof(pre));
queue<int>que;
que.push(sx);
pre[sx] = 1;
while(!que.empty()){
int kk = que.front();
que.pop();
for(int i = head[kk]; i != -1; i = edge[i].next){
int v = edge[i].to;
if(!pre[v]&&edge[i].c){
pre[v] = pre[kk] + 1;
que.push(v);
}
}
}
return pre[ex] != 0;
}
int DFS(int pos, int flow){
if(pos == ex || flow == 0)
return flow;
int f = flow;
for(int i = head[pos]; i != -1; i = edge[i].next){
int tmp, v = edge[i].to;
if(edge[i].c && pre[pos] + 1 == pre[v] && (tmp = DFS(v, min(edge[i].c, flow)))>0){
edge[i].c -= tmp;
edge[i^1].c += tmp;
flow -= tmp;
if(flow == 0){
break;
}
}
}
return f - flow;
}
int Dinic(int sx, int ex){
int flow = 0;
while(BFS(sx, ex)){
flow += DFS(sx, inf);
}
return flow;
}
int main(){
while(~scanf("%d%d",&m, &n)){
init();
read();
printf("%d\n", Dinic(sx, ex));
}
return 0;
}

DINIC优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e5+7;
const int inf = 0x3f3f3f3f;
int n, m, sx, ex, cnt;
int head[maxn], pre[maxn], cur[maxn];
struct EDGE{
int u, next, to, c;
}edge[maxn<<3];
void add_edge(int u, int v, int c){
edge[cnt].u = u;
edge[cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].c = c<=inf ? c : inf;
head[u] = cnt++;
}
void add(int u, int v, int c){
add_edge(u, v, c);
add_edge(v, u, 0);//双向边容量为c
}
void init(){
//memset(edge, 0, sizeof(edge));
memset(head, -1, sizeof(head));
cnt = 0;
}
void read(){
sx = 1, ex = n;
for(int i = 0; i < m; i++){
int u, v, w;
scanf("%d%d%d",&u, &v, &w);
add(u, v, w);
}
}
bool BFS(int sx, int ex){
memset(pre, 0, sizeof(pre));
queue<int>que;
que.push(sx);
pre[sx] = 1;
while(!que.empty()){
int kk = que.front();
que.pop();
for(int& i = cur[kk]; i != -1; i = edge[i].next){
int v = edge[i].to;
if(!pre[v]&&edge[i].c){
pre[v] = pre[kk] + 1;
que.push(v);
}
}
}
return pre[ex] != 0;
}
int DFS(int pos, int flow){
if(pos == ex || flow == 0)
return flow;
int f = flow;
for(int i = head[pos]; i != -1; i = edge[i].next){
int tmp, v = edge[i].to;
if(edge[i].c && pre[pos] + 1 == pre[v] && (tmp = DFS(v, min(edge[i].c, flow)))>0){
edge[i].c -= tmp;
edge[i^1].c += tmp;
flow -= tmp;
if(flow == 0){
break;
}
}
}
return f - flow;
}
int Dinic(int sx, int ex){
int flow = 0;
while(BFS(sx, ex)){
memcpy(cur, head, sizeof(head));
flow += DFS(sx, inf);
}
return flow;
}
int main(){
while(~scanf("%d%d",&m, &n)){
init();
read();
printf("%d\n", Dinic(sx, ex));
}
return 0;
}

DINIC(邻接矩阵)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 307;
struct NODE{
int c;
int f;
};
int sx,ex;
int pre[maxn];
NODE road[maxn][maxn];
int n, m, N;
bool BFS(){
memset(pre,0,sizeof(pre));
queue<int>q;
q.push(sx);
pre[sx] = 1;
while(!q.empty()){
int d = q.front();
q.pop();
for(int i = 1;i<=N;i++){
if(!pre[i]&&road[d][i].c-road[d][i].f){
pre[i] = pre[d] + 1;
q.push(i);
}
}
}
return pre[ex]!=0;
}
int dfs(int pos, int flow){
int f = flow;
if(pos==ex)
return flow;
for(int i = 1; i <= N; i++){
if(road[pos][i].c - road[pos][i].f && pre[pos] + 1 == pre[i]){
int a = road[pos][i].c - road[pos][i].f;
int t = dfs(i, min(a, flow));
road[pos][i].f += t;
road[i][pos].f -= t;
flow -= t;
}
}
return f - flow;
}
int dinic(){
int sum = 0;
while(BFS()){
sum+=dfs(sx,inf);
}
return sum;
}
void init(){
N = n;
sx = 0;
ex = N;
memset(road,0,sizeof(road));
}
void read(){
int u,v,w;
for(int i = 1;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
road[u][v].c+=w;
}
}
int main(){
while(~scanf("%d%d",&m,&n)){
init();
read();
printf("%d\n",dinic());
}
return 0;
}

ISAP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include<cstdio>
#include<cctype>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
int read() {
int x=0,f=1;
char c=getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const int maxn=205;
const int maxm=205;
const int inf=2e9+7;
struct edge {
int v,w,nxt;
} e[maxm<<1];
int h[maxn],tot,n,m,gap[maxn],last[maxn],d[maxn],que[maxn],ql,qr;
vector<int> inv[maxn];
void add(int u,int v,int w) {
e[++tot]=(edge){v,w,h[u]};
h[u]=tot;
e[++tot]=(edge){u,0,h[v]};
h[v]=tot;
}
void init(int s,int t) {
memset(gap,0,sizeof gap),memset(d,0,sizeof d),++gap[d[t]=1];
for (int i=1;i<=n;++i) last[i]=h[i];
que[ql=qr=1]=t;
while (ql<=qr) {
int x=que[ql++];
for (int i=h[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v) if (!d[v]) ++gap[d[v]=d[x]+1],que[++qr]=v;
}
}
int aug(int x,int s,int t,int mi) {
if (x==t) return mi;
int flow=0;
for (int &i=last[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v) if (d[x]==d[v]+1) {
int tmp=aug(v,s,t,min(mi,e[i].w));
flow+=tmp,mi-=tmp,e[i].w-=tmp,e[i^1].w+=tmp;
if (!mi) return flow;
}
if (!(--gap[d[x]])) d[s]=n+1;
++gap[++d[x]],last[x]=h[x];
return flow;
}
int maxflow(int s,int t) {
init(s,t);
int ret=aug(s,s,t,inf);
while (d[s]<=n) ret+=aug(s,s,t,inf);
return ret;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
while (~scanf("%d%d",&m,&n)) {
tot=1,memset(h,0,sizeof h);
for (int i=1;i<=n;++i) inv[i].clear();
for (int i=1;i<=m;++i) {
int u=read(),v=read(),w=read();
add(u,v,w);
if (w) inv[v].push_back(u);
}
int ans=maxflow(1,n);
printf("%d\n",ans);
}
return 0;
}

MCMF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxm = 1e5+7;
const int maxn = 1e4+7;
const int inf = 0x3f3f3f3f;
int n, m, cnt, sx, ex;
int head[maxn], pre[maxn], dis[maxn];
bool vis[maxn];
struct EDGE{
int next;
int to;
int w;
int c;
}edge[maxm];
void init(){
sx = 0;
ex = 1;
cnt = 0;
memset(edge, 0, sizeof(edge));
memset(head, -1, sizeof(head));
}
void add_edge(int u, int v, int c, int w){
edge[cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].c = c<=inf ? c : inf;
edge[cnt].w = w;
head[u] = cnt++;
}
void add(int u, int v, int c, int w){
add_edge(u, v, c, w);
add_edge(v, u, 0, -w);
}
bool SPFA(int sx, int ex){
memset(pre, -1, sizeof(pre));
memset(dis, inf, sizeof(dis));
memset(vis, false, sizeof(vis));
dis[sx] = 0;
queue<int>que;
que.push(sx);
while(!que.empty()){
int kk = que.front();
que.pop();
vis[kk] = false;
for(int i = head[kk]; i != -1; i = edge[i].next){
EDGE tmp = edge[i];
if(tmp.c && dis[tmp.to]>dis[kk]+tmp.w){
dis[tmp.to] = dis[kk] + tmp.w;
pre[tmp.to] = i;
if(!vis[tmp.to]){
vis[tmp.to] = true;
que.push(tmp.to);
}
}
}
}
return pre[ex] != -1;
}
int MCMF(int sx, int ex){
int flow = 0, cost = 0;
while(SPFA(sx, ex)){
int min_flow = inf;
for(int i = pre[ex]; i != -1; i = pre[edge[i^1].to]){
min_flow = min(min_flow, edge[i].c);
}
for(int i = pre[ex]; i != -1; i = pre[edge[i^1].to]){
edge[i].c -= min_flow;
edge[i^1].c += min_flow;
cost += min_flow * edge[i].w;
}
flow += min_flow;
}
return cost;
}
void read(){
int u, v, c, w;
ex = n+1;
for(int i = 0;i<m;i++){
scanf("%d%d%d%d",&u,&v,&c,&w);
add(u,v,c, w);
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
if(n+m==0){
break;
}
init();
read();
printf("%d\n",MCMF(sx, ex));
}
return 0;
}

匹配

匈牙利算法(邻接矩阵)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 107;
int N, K;
int edge[maxn][maxn], head[maxn];
bool vis[maxn];
void init(){
memset(edge, 0, sizeof(edge));
memset(head, 0, sizeof(head));
}
bool find_edge(int x) {
for (int i = 1; i <= N; i++) {
if (edge[x][i] && !vis[i]) {
vis[i] = true;
if (!head[i] || find_edge(head[i])) {
head[i] = x;
return true;
}
}
}
return false;
}
int Magyar(int N){
int ans = 0;
for (int i = 1; i <= N; i++) {
memset(vis, false, sizeof(vis));
if (find_edge(i)) {
ans++;
}
}
return ans;
}
int main() {
while (cin >> N >> K) {
int x, y;
for (int i = 1; i <= K; i++){
cin >> x >> y;
edge[x][y] = 1;
}
cout << Magyar(N) << endl;
}
return 0;
}

匈牙利算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include<bits/stdc++.h>
using namespace std;
const int maxn = 107;
int T, N, m;
int head[maxn], link[maxn];
bool vis[maxn];
int cnt;
struct EDGE{
int next, u, to, w;
}edge[maxn];
void add(int u, int v, int w){
edge[cnt].next = head[u];
edge[cnt].u = u;
edge[cnt].to = v;
edge[cnt].w = w;
head[u] = cnt++;
}
void init(){
memset(edge, 0, sizeof(edge));
memset(link, 0, sizeof(link));
memset(head, -1, sizeof(head));
cnt = 0;
}
bool find_edge(int x){
for(int i = head[x]; i!= -1; i = edge[i].next){
int v = edge[i].to;
if(!vis[v]){
vis[v] = true;
if (!link[v] || find_edge(link[v])) {
link[v] = x;
return true;
}
}
}
return false;
}
int Magyar(int N){
int ans = 0;
for (int i = 1; i <= N; i++) {
memset(vis, false, sizeof(vis));
if (find_edge(i)) {
ans++;
}
}
return ans;
}
int solve(){
int ans = Magyar(N);
return ans;
}
void read(){
scanf("%d%d",&N, &m);
while(m--){
int x, y;
scanf("%d%d",&x, &y);
add(x, y, 1);
}
}
int main(){
scanf("%d", &T);
while(T--){
init();
read();
printf("%d\n", solve());
}
return 0;
}

KM算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 207;
const int maxm = 30007;
const int inf = 0x3f3f3f3f;
int n, m;
int minD, cntx, cnty, edge[maxn][maxn];
bool visx[maxn], visy[maxn];
int linkx[maxn], link[maxn], wx[maxn], wy[maxn];
bool dfs(int x){ //匈牙利算法找增广路径
visx[x] = true;
for(int i = 1; i <= cnty; i++){
if(!visy[i]){
int t = wx[x] + wy[i] - edge[x][i];
if(t == 0) {
visy[i] = true;
if(link[i] == 0 || dfs(link[i])){
linkx[x] = i;
link[i] = x;
return true;
}
}
else if(t > 0){ //找出边权与顶标和的最小的差值
if(t < minD){
minD = t;
}
}
}
}
return false;
}
int km(){
memset(linkx, 0, sizeof linkx); //linkx[i]表示与X部中点i匹配的点
memset(link, 0, sizeof link);
memset(wy, 0, sizeof(wy));
for(int i = 1; i <= cntx; i++){
wx[i] = -inf;
for(int j = 1; j <= cnty; j++){
if(wx[i] < edge[i][j]){
wx[i] = edge[i][j];//初始化为权值最大的边的权值
}
}
}
for(int i = 1; i <= cntx; i++){
while(1){
minD = inf;
memset(visx, false, sizeof visx);
memset(visy, false, sizeof visy);
if(dfs(i)){
break;
}
for(int j = 1; j <= cntx; j++){ //将交错树中X部的点的顶标减去minz
if(visx[j]){
wx[j] -= minD;
}
}
for(int j = 1; j <= cnty; j++){ //将交错树中Y部的点的顶标加上minz
if(visy[j]){
wy[j] += minD;
}
}
}
}
int ans = 0;
for(int i = 1; i <= cnty; i ++){
if(link[i]!=0){
ans += edge[link[i]][i];
}
}
return ans;
}
int main(){
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &m);
cntx = cnty = n;
memset(edge, 0, sizeof(edge));
for(int i = 0; i < m; i++){
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
edge[u][v] = max(edge[u][v], w);
}
printf("%d\n", km());
}
return 0;
}

KM算法最小权匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 207;
const int maxm = 30007;
const int inf = 0x3f3f3f3f;
int n, m;
int minD, cntx, cnty, edge[maxn][maxn];
bool visx[maxn], visy[maxn];
int linkx[maxn], link[maxn], wx[maxn], wy[maxn];
bool dfs(int x){ //匈牙利算法找增广路径
visx[x] = true;
for(int i = 1; i <= cnty; i++){
if(!visy[i]){
int t = wx[x] + wy[i] - edge[x][i];
if(t == 0) {
visy[i] = true;
if(link[i] == 0 || dfs(link[i])){
linkx[x] = i;
link[i] = x;
return true;
}
}
else if(t > 0){ //找出边权与顶标和的最小的差值
if(t < minD){
minD = t;
}
}
}
}
return false;
}
int km(){
memset(linkx, 0, sizeof linkx); //linkx[i]表示与X部中点i匹配的点
memset(link, 0, sizeof link);
memset(wy, 0, sizeof(wy));
for(int i = 1; i <= cntx; i++){
wx[i] = -inf;
for(int j = 1; j <= cnty; j++){
if(wx[i] < edge[i][j]){
wx[i] = edge[i][j];//初始化为权值最大的边的权值
}
}
}
for(int i = 1; i <= cntx; i++){
while(1){
minD = inf;
memset(visx, false, sizeof visx);
memset(visy, false, sizeof visy);
if(dfs(i)){
break;
}
for(int j = 1; j <= cntx; j++){ //将交错树中X部的点的顶标减去minz
if(visx[j]){
wx[j] -= minD;
}
}
for(int j = 1; j <= cnty; j++){ //将交错树中Y部的点的顶标加上minz
if(visy[j]){
wy[j] += minD;
}
}
}
}
int ans = 0;
for(int i = 1; i <= cnty; i ++){
if(link[i]!=0&&edge[link[i]][i]!=-inf){
ans += edge[link[i]][i];
}
}
return -ans;
}
int main(){
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &m);
cntx = cnty = n;
for(int i = 0; i <= cntx; i++){
for(int j = 0; j <= cnty; j++){
edge[i][j] = -inf;
}
}
for(int i = 0; i < m; i++){
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
edge[u][v] = max(edge[u][v], -w);
}
printf("%d\n", km());
}
return 0;
}

KM算法最小权匹配优化版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 207;
const int maxm = 30007;
const int inf = 0x3f3f3f3f;
int n, m;
int minD, cntx, cnty, edge[maxn][maxn];
bool visx[maxn], visy[maxn];
int linkx[maxn], link[maxn], wx[maxn], wy[maxn];
bool dfs(int x){ //匈牙利算法找增广路径
visx[x] = true;
for(int i = 1; i <= cnty; i++){
if(!visy[i]){
int t = wx[x] + wy[i] - edge[x][i];
if(t == 0) {
visy[i] = true;
if(link[i] == 0 || dfs(link[i])){
linkx[x] = i;
link[i] = x;
return true;
}
}
else if(t > 0){ //找出边权与顶标和的最小的差值
if(t < minD){
minD = t;
}
}
}
}
return false;
}
int km(){
memset(linkx, 0, sizeof linkx); //linkx[i]表示与X部中点i匹配的点
memset(link, 0, sizeof link);
memset(wy, 0, sizeof(wy));
for(int i = 1; i <= cntx; i++){
wx[i] = -inf;
for(int j = 1; j <= cnty; j++){
if(wx[i] < edge[i][j]){
wx[i] = edge[i][j];//初始化为权值最大的边的权值
}
}
}
for(int i = 1; i <= cntx; i++){
while(1){
minD = inf;
memset(visx, false, sizeof visx);
memset(visy, false, sizeof visy);
if(dfs(i)){
break;
}
for(int j = 1; j <= cntx; j++){ //将交错树中X部的点的顶标减去minz
if(visx[j]){
wx[j] -= minD;
}
}
for(int j = 1; j <= cnty; j++){ //将交错树中Y部的点的顶标加上minz
if(visy[j]){
wy[j] += minD;
}
}
}
}
int ans = 0;
for(int i = 1; i <= cnty; i ++){
if(link[i]!=0&&edge[link[i]][i]!=-inf){
ans += edge[link[i]][i];
}
}
return -ans;
}
int main(){
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &m);
cntx = cnty = n;
for(int i = 0; i <= cntx; i++){
for(int j = 0; j <= cnty; j++){
edge[i][j] = -inf;
}
}
for(int i = 0; i < m; i++){
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
edge[u][v] = max(edge[u][v], -w);
}
printf("%d\n", km());
}
return 0;
}

强连通

Tarjan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 7;
const int inf = 0x3f3f3f3f;
int n, m;
int head[maxn], cnt, top, dfs_num, col_num;
int dfn[maxn], low[maxn], Stack[maxn], color[maxn];
bool vis[maxn];
struct EDGE{
int next, to, u;
}edge[maxn<<3];
void add(int u, int v){
edge[cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].u = u;
head[u] = cnt++;
}
void Tarjan(int x){
dfn[x] = ++dfs_num;
low[x] = dfs_num;
vis[x] = true; //是否在栈中
Stack[++top] = x;
for(int i = head[x]; i != -1; i = edge[i].next){
int v = edge[i].to;
if(!dfn[v]){
Tarjan(v);
low[x] = min(low[x], low[v]);
}
else if(vis[v]){
low[x] = min(low[x], dfn[v]);
}
}
if(dfn[x] == low[x]){ //构成强连通分量
vis[x] = false;
color[x] = ++col_num; //染色
while(Stack[top] != x){ //清空
color[Stack[top]] = col_num;
vis [ Stack[ top-- ] ] = false ;
}
top--;
}
}
void init(){
top = dfs_num = col_num = cnt = 0;
memset(head, -1, sizeof(head));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(color, 0, sizeof(color));
memset(vis, false, sizeof(vis));
}
void read(){
int u, v;
for(int i = 0; i < m; i++){
scanf("%d%d", &u, &v);
add(u, v);
}
}
void solve(){
for(int i = 1; i <= n; i++){
if(!color[i]){
Tarjan(i);
}
}
if(col_num != 1){
printf("No\n");
}
else{
printf("Yes\n");
}
}
int main(){
while(~scanf("%d%d", &n, &m) && n+m){
init();
read();
solve();
}
return 0;
}

Tarjan缩点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <iostream>
#include <cstring>
#include <cstdio>
#define MAXN 10010
#define MAXE 100010
using namespace std;
int head[MAXN],tot1,tot2;
struct Edge{
int u,v,next;
}e1[MAXE],e2[MAXN];
void addEdge(int u,int v,Edge* edge,int& tol){
edge[tol].u=u;edge[tol].v=v;
edge[tol].next=head[u];head[u]=tol++;
}
int n,m;
int low[MAXN],dfn[MAXN],stack[MAXN],belong[MAXN],num[MAXN];
bool instack[MAXN];
int scc,top,INDEX;
void Tarjan(int u){
int v;
low[u]=dfn[u]=++INDEX;
stack[top++]=u;
instack[u]=true;
for(int i=head[u];i!=-1;i=e1[i].next){
v=e1[i].v;
if(!dfn[v]){
Tarjan(v);
if(low[u]>low[v]) low[u]=low[v];
}
else if(instack[v]&&low[u]>dfn[v])
low[u]=dfn[v];
}
if(low[u]==dfn[u]){
++scc;
do{
v=stack[--top];
instack[v]=false;
belong[v]=scc;
num[scc]++;
}while(u!=v);
}
}
int inde[MAXN],outde[MAXN];
void solve(){
memset(dfn,0,sizeof(dfn));
memset(instack,false,sizeof(instack));
memset(num,0,sizeof(num));
scc=top=INDEX=0;
for(int i=1;i<=n;++i)
if(!dfn[i]) Tarjan(i);
tot2=0;memset(head,-1,sizeof(head));
memset(inde,0,sizeof(inde));
memset(outde,0,sizeof(outde));
int u,v;
for(int i=0;i<m;++i){
u=belong[e1[i].u];
v=belong[e1[i].v];
if(u!=v){
addEdge(u,v,e2,tot2);
inde[v]++;
outde[u]++;
}
}
int a=0,b=0;
for(int i=1;i<=scc;++i){
if(!inde[i]) a++;
if(!outde[i]) b++;
}
if(scc==1)printf("0\n");
else
printf("%d\n",max(a,b));
}
int main()
{ int zushu;
scanf("%d",&zushu);
while(zushu--){
scanf("%d%d",&n,&m);
tot1=0;memset(head,-1,sizeof(head));
int u,v;
for(int i=0;i<m;++i){
scanf("%d%d",&u,&v);
addEdge(u,v,e1,tot1);
}
solve();
}
return 0;
}

2-SAT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
HDU 3622

/*
HDU 3622
题意:给n对炸弹可以放置的位置(每个位置为一个二维平面上的点),
每次放置炸弹是时只能选择这一对中的其中一个点,每个炸弹爆炸
的范围半径都一样,控制爆炸的半径使得所有的爆炸范围都不相
交(可以相切),求解这个最大半径.
首先二分最大半径值,然后2-sat构图判断其可行性,对于每
两队位置(u,uu)和(v,vv),如果u和v之间的距离小于2*id,也就
是说位置u和位置v处不能同时防止炸弹(两范围相交),所以连边(u,vv)
和(v,uu),求解强连通分量判断可行性.


注意精度问题
*/

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<iostream>
#include<math.h>
using namespace std;
const int MAXN=210;
const int MAXM=40005;//边的最大数
const double eps=1e-5;

struct Edge
{
int to,next;
}edge1[MAXM],edge2[MAXM];
int head1[MAXN];
int head2[MAXN];
int tol1,tol2;
bool vis1[MAXN],vis2[MAXN];
int Belong[MAXN];//连通分量标记
int T[MAXN];//dfs结点结束时间
int Bcnt,Tcnt;
void add(int a,int b)//原图和逆图都要添加
{
edge1[tol1].to=b;
edge1[tol1].next=head1[a];
head1[a]=tol1++;
edge2[tol2].to=a;
edge2[tol2].next=head2[b];
head2[b]=tol2++;
}
void init()//建图前初始化
{
memset(head1,-1,sizeof(head1));
memset(head2,-1,sizeof(head2));
memset(vis1,false,sizeof(vis1));
memset(vis2,false,sizeof(vis2));
tol1=tol2=0;
Bcnt=Tcnt=0;
}
void dfs1(int x)//对原图进行dfs,算出每个结点的结束时间,哪个点开始无所谓
{
vis1[x]=true;
int j;
for(int j=head1[x];j!=-1;j=edge1[j].next)
if(!vis1[edge1[j].to])
dfs1(edge1[j].to);
T[Tcnt++]=x;
}
void dfs2(int x)
{
vis2[x]=true;
Belong[x]=Bcnt;
int j;
for(j=head2[x];j!=-1;j=edge2[j].next)
if(!vis2[edge2[j].to])
dfs2(edge2[j].to);
}

struct Point
{
int x,y;
}s[MAXN];
double dist(Point a,Point b)
{
return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

bool ok(int n)//判断可行性
{
for(int i=0;i<2*n;i++)
if(!vis1[i])
dfs1(i);
for(int i=Tcnt-1;i>=0;i--)
if(!vis2[T[i]])//这个别写错,是vis2[T[i]]
{
dfs2(T[i]);
Bcnt++;
}
for(int i=0;i<=2*n-2;i+=2)
if(Belong[i]==Belong[i+1])
return false;
return true;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n;
double left,right,mid;
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++)
scanf("%d%d%d%d",&s[2*i].x,&s[2*i].y,&s[2*i+1].x,&s[2*i+1].y);
left=0;
right=40000.0;
while(right-left>=eps)
{
mid=(left+right)/2;
init();
for(int i=0;i<2*n-2;i++)
{
int t;
if(i%2==0)t=i+2;
else t=i+1;
for(int j=t;j<2*n;j++)
if(dist(s[i],s[j])<2*mid)//冲突了
{
add(i,j^1);
add(j,i^1);//注意顺序不能变的
}
}
if(ok(n))left=mid;
else right=mid;
}
printf("%.2lf\n",right);
}
return 0;
}

数学

数论

gcd

1
2
3
int gcd(int a, int b){
return !b ? a : gcd(b, a%b);
}

exgcd

1
2
3
4
5
6
7
8
9
int exgcd(int a,int b,int &x,int &y){
if (b==0){
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}

中国剩余定理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
using namespace std;

int Extended_Euclid(int a,int b,int &x,int &y) //扩展欧几里得算法
{
int d;
if(b==0)
{
x=1;y=0;
return a;
}
d=Extended_Euclid(b,a%b,y,x);
y-=a/b*x;
return d;
}

int Chinese_Remainder(int a[],int w[],int len) //中国剩余定理 a[]存放余数 w[]存放两两互质的数
{
int i,d,x,y,m,n,ret;
ret=0;
n=1;
for (i=0;i<len;i++)
n*=w[i];
for (i=0;i<len;i++)
{
m=n/w[i];
d=Extended_Euclid(w[i],m,x,y);
ret=(ret+y*m*a[i])%n;
}
return (n+ret%n)%n;
}


int main()
{
int n,i;
int w[15],b[15];
while (scanf("%d",&n),n)
{
for (i=0;i<n;i++)
{
scanf("%d%d",&w[i],&b[i]);
}
printf("%d/n",Chinese_Remainder(b,w,n));
}
return 0;
}

欧拉函数

1
2
3
4
5
6
7
8
9
10
11
12
13
int oula(int n)
{
int rea=n;
for(int i=2; i<=n; i++)
if(n%i==0)//第一次找到的必为素因子
{
rea=rea-rea/i;
do
n/=i;//把该素因子全部约掉
while(n%i==0);
}
return rea;
}

欧拉筛

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int prime[maxn];
int visit[maxn];
void Prime(){
mem(visit,0);
mem(prime, 0);
for (int i = 2;i <= maxn; i++) {
cout<<" i = "<<i<<endl;
if (!visit[i]) {
prime[++prime[0]] = i; //纪录素数, 这个prime[0] 相当于 cnt,用来计数
}
for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++) {
visit[i*prime[j]] = 1;
if (i % prime[j] == 0) {
break;
}
}
}
}

卡特兰数

卡特兰数打表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
unsigned long long ctl[34] = {0,1};
void calc()
{
int i;
for(i = 2; i < 34; i ++)
ctl[i] = ctl[i-1]*(4*i-2)/(i+1);
}

int main()
{
int i;
calc();
for(i = 0; i < 34; i ++)
printf("%d: %llu\n",i, ctl[i]);
}

卡特兰数表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include<stdio.h>
#include<string.h>
#include<string>
#include<iostream>
using namespace std;
string catalan[]=
{
"1",
"2",
"5",
"14",
"42",
"132",
"429",
"1430",
"4862",
"16796",
"58786",
"208012",
"742900",
"2674440",
"9694845",
"35357670",
"129644790",
"477638700",
"1767263190",
"6564120420",
"24466267020",
"91482563640",
"343059613650",
"1289904147324",
"4861946401452",
"18367353072152",
"69533550916004",
"263747951750360",
"1002242216651368",
"3814986502092304",
"14544636039226909",
"55534064877048198",
"212336130412243110",
"812944042149730764",
"3116285494907301262",
"11959798385860453492",
"45950804324621742364",
"176733862787006701400",
"680425371729975800390",
"2622127042276492108820",
"10113918591637898134020",
"39044429911904443959240",
"150853479205085351660700",
"583300119592996693088040",
"2257117854077248073253720",
"8740328711533173390046320",
"33868773757191046886429490",
"131327898242169365477991900",
"509552245179617138054608572",
"1978261657756160653623774456",
"7684785670514316385230816156",
"29869166945772625950142417512",
"116157871455782434250553845880",
"451959718027953471447609509424",
"1759414616608818870992479875972",
"6852456927844873497549658464312",
"26700952856774851904245220912664",
"104088460289122304033498318812080",
"405944995127576985730643443367112",
"1583850964596120042686772779038896",
"6182127958584855650487080847216336",
"24139737743045626825711458546273312",
"94295850558771979787935384946380125",
"368479169875816659479009042713546950",
"1440418573150919668872489894243865350",
"5632681584560312734993915705849145100",
"22033725021956517463358552614056949950",
"86218923998960285726185640663701108500",
"337485502510215975556783793455058624700",
"1321422108420282270489942177190229544600",
"5175569924646105559418940193995065716350",
"20276890389709399862928998568254641025700",
"79463489365077377841208237632349268884500",
"311496878311103321137536291518809134027240",
"1221395654430378811828760722007962130791020",
"4790408930363303911328386208394864461024520",
"18793142726809884575211361279087545193250040",
"73745243611532458459690151854647329239335600",
"289450081175264899454283846029490767264392230",
"1136359577947336271931632877004667456667613940",
"4462290049988320482463241297506133183499654740",
"17526585015616776834735140517915655636396234280",
"68854441132780194707888052034668647142985206100",
"270557451039395118028642463289168566420671280440",
"1063353702922273835973036658043476458723103404520",
"4180080073556524734514695828170907458428751314320",
"16435314834665426797069144960762886143367590394940",
"64633260585762914370496637486146181462681535261000",
"254224158304000796523953440778841647086547372026600",
"1000134600800354781929399250536541864362461089950800",
"3935312233584004685417853572763349509774031680023800",
"15487357822491889407128326963778343232013931127835600",
"60960876535340415751462563580829648891969728907438000",
"239993345518077005168915776623476723006280827488229600",
"944973797977428207852605870454939596837230758234904050",
"3721443204405954385563870541379246659709506697378694300",
"14657929356129575437016877846657032761712954950899755100",
"57743358069601357782187700608042856334020731624756611000",
"227508830794229349661819540395688853956041682601541047340",
"896519947090131496687170070074100632420837521538745909320"
};

int main(){
int i;
while(scanf("%d",&i)!=EOF){
cout<<catalan[i-1]<<endl;
}
}

斯特林数

第一类斯特林数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include<bits/stdc++.h>
using namespace std;
#define RI register int
const int N=200005,mod=998244353,G=3;
int n,A,B,ans,a[18][N],rev[N];
int ksm(int x,int y) {
int re=1;
for(RI i=y;i;i>>=1,x=1LL*x*x%mod) if(i&1) re=1LL*re*x%mod;
return re;
}
void NTT(int *a,int n,int x) {
for(RI i=0;i<n;++i) if(rev[i]>i) swap(a[i],a[rev[i]]);
for(RI i=1;i<n;i<<=1) {
int gn=ksm(G,(mod-1)/(i<<1));
for(RI j=0;j<n;j+=(i<<1)) {
int g=1,t1,t2;
for(RI k=0;k<i;++k,g=1LL*g*gn%mod) {
t1=a[j+k],t2=1LL*g*a[j+i+k]%mod;
a[j+k]=(t1+t2)%mod,a[j+i+k]=(t1-t2+mod)%mod;
}
}
}
if(x==1) return;
int inv=ksm(n,mod-2);reverse(a+1,a+n);//a+1!!!
for(RI i=0;i<n;++i) a[i]=1LL*a[i]*inv%mod;
}
void work(int s,int t,int d) {
if(s==t) {a[d][0]=s,a[d][1]=1;return;}
int mid=(s+t)>>1,len=0,kn=1;
work(s,mid,d+1);
for(RI i=0;i<=mid-s+1;++i) a[d][i]=a[d+1][i];
work(mid+1,t,d+1);
while(kn<=t-s+1) kn<<=1,++len;
for(RI i=0;i<kn;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(len-1));
for(RI i=mid-s+2;i<kn;++i) a[d][i]=0;
for(RI i=t-mid+1;i<kn;++i) a[d+1][i]=0;
NTT(a[d],kn,1),NTT(a[d+1],kn,1);
for(RI i=0;i<kn;++i) a[d][i]=1LL*a[d][i]*a[d+1][i]%mod;
NTT(a[d],kn,-1);
}
int C(int d,int u) {
int k1=1,k2=1;
for(RI i=d-u+1;i<=d;++i) k1=1LL*k1*i%mod;
for(RI i=1;i<=u;++i) k2=1LL*k2*i%mod;
return 1LL*k1*ksm(k2,mod-2)%mod;
}
int main()
{
scanf("%d%d%d",&n,&A,&B);
if(!A||!B||A+B-2>n-1) {puts("0");return 0;}
if(n==1) {puts("1");return 0;}
work(0,n-2,0);
ans=1LL*a[0][A+B-2]*C(A+B-2,B-1)%mod;
printf("%d\n",ans);
return 0;
}

第二类斯特林数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<bits/stdc++.h>
using namespace std;
#define RI register int
const int mod=998244353,G=3,N=262150;
int n,kn,len,ans;
int a[N],b[N],fac[N],ni[N],rev[N];
int ksm(int x,int y) {
int re=1;
for(;y;y>>=1,x=1LL*x*x%mod) if(y&1) re=1LL*re*x%mod;
return re;
}
void NTT(int *a,int n,int x) {
for(RI i=0;i<n;++i) if(rev[i]>i) swap(a[i],a[rev[i]]);
for(RI i=1;i<n;i<<=1) {
int gn=ksm(G,(mod-1)/(i<<1));
for(RI j=0;j<n;j+=(i<<1)) {
int g=1,t1,t2;
for(RI k=0;k<i;++k,g=1LL*g*gn%mod) {
t1=a[j+k],t2=1LL*g*a[j+i+k]%mod;
a[j+k]=(t1+t2)%mod,a[j+i+k]=(t1-t2+mod)%mod;
}
}
}
if(x==1) return;
int inv=ksm(n,mod-2);reverse(a+1,a+n);
for(RI i=0;i<n;++i) a[i]=1LL*a[i]*inv%mod;
}
int main()
{
scanf("%d",&n);
fac[0]=1;for(RI i=1;i<=n;++i) fac[i]=1LL*fac[i-1]*i%mod;
ni[n]=ksm(fac[n],mod-2);
for(RI i=n-1;i>=0;--i) ni[i]=1LL*ni[i+1]*(i+1)%mod;
for(RI i=0;i<=n;++i) {
a[i]=1LL*(1-2*(i&1)+mod)%mod*ni[i]%mod;
if(i!=1) b[i]=1LL*(ksm(i,n+1)-1+mod)%mod*ni[i]%mod*ksm(i-1+mod,mod-2)%mod;
else b[i]=n+1;
}
kn=1;while(kn<=n+n) kn<<=1,++len;
for(RI i=0;i<kn;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(len-1));
NTT(a,kn,1),NTT(b,kn,1);
for(RI i=0;i<kn;++i) a[i]=1LL*a[i]*b[i]%mod;
NTT(a,kn,-1);
for(RI i=0,j=1;i<=n;++i,j=(j+j)%mod)
ans=(ans+1LL*j*fac[i]%mod*a[i]%mod)%mod;
printf("%d\n",ans);
return 0;
}

逆元

逆元(Inverse element)就是在mod意义下,不能直接除以一个数,而要乘以它的逆元。
比如a∗b≡1(modp)a∗b≡1(modp),那么a,b互为模n意义下的逆元,比如你要算x/a,就可以改成x*b%p

观察a∗b≡1(modp)a∗b≡1(modp),变形为a∗b+k∗p=1a∗b+k∗p=1,就可以用扩展欧几里得算法求a了,同时这里也说明了a和p只有在互素的情况下才存在逆元。

注意
在下面所有的算法中,最好先把除数取个模再运算。

扩展欧几里得算法

原理
a∗b≡1(modp)a∗b≡1(modp)
a∗b+k∗p=1a∗b+k∗p=1
然后a就是我们要求的逆元,最终得到一个正数a的话就要对a mod p,因为a加上mp的时侯k减少mb可以使得等式依然成立。

如果你不想让逆元为正数,那么直接返回x也是可以正确的逆元

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
LL exgcd(LL a,LL b,LL &x,LL &y)//扩展欧几里得算法 
{
if(b==0)
{
x=1,y=0;
return a;
}
LL ret=exgcd(b,a%b,y,x);
y-=a/b*x;
return ret;
}
LL getInv(int a,int mod)//求a在mod下的逆元,不存在逆元返回-1
{
LL x,y;
LL d=exgcd(a,mod,x,y);
return d==1?(x%mod+mod)%mod:-1;
}

注意:返回的时候可以改成(x+mod)%mod,因为扩展欧几里得算法算出来的x应该不会太大.

性能分析:

时间复杂度:O(logn)(实际是斐波那契数列)
适用范围:只要存在逆元即可求,适用于个数不多但是mod很大的时候,也是最常见的一种求逆元的方法。

费马小定理/欧拉定理

原理
费马小定理:若p为素数,则有ap−1≡1(modp)ap−1≡1(modp)
ap−2∗a≡1(modp)ap−2∗a≡1(modp)
ap−2ap−2就是a在mod p意义下的逆元啦。

欧拉定理:若a、p互素,则有aφ(p)≡1(modp)aφ(p)≡1(modp)(费马小定理的一般形式)
aφ(p)∗a≡1(modp)aφ(p)∗a≡1(modp)
aφ(p)−1aφ(p)−1就是a在mod p意义下的逆元啦。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
LL qkpow(LL a,LL p,LL mod)
{
LL t=1,tt=a%mod;
while(p)
{
if(p&1)t=t*tt%mod;
tt=tt*tt%mod;
p>>=1;
}
return t;
}
LL getInv(LL a,LL mod)
{
return qkpow(a,mod-2,mod);
}

性能分析:

O(logmod)
适用范围:一般在mod是个素数的时候用,比扩欧快一点而且好写。
但是如果是合数,相信一般没人无聊到去算个欧拉函数。

递推求逆元

原理
p是模数,i是待求的逆元,我们求的是i−1i−1在mod p意义下的值
p=k∗i+rp=k∗i+r令 r < i,则k=p/i,r=p%i
k∗i+r≡0(modp)k∗i+r≡0(modp)
k∗r−1+i−1≡0(modp)k∗r−1+i−1≡0(modp)
i−1≡−k∗r−1(modp)i−1≡−k∗r−1(modp)
i−1≡−p/i∗inv[pmodi]i−1≡−p/i∗inv[pmodi]
嗯。。好难看的公式
说白了就是:inv[i]=-(mod/i)*inv[i%mod]
然后边界是inv[1]=1
这不仅为我们提供了一个线性求逆元的方法,也提供了一种O(logmod)求逆元的方法

代码
线性求逆元

1
2
3
4
5
6
7
LL inv[mod+5];
void getInv(LL mod)
{
inv[1]=1;
for(int i=2;i<mod;i++)
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}

注意:

调用前要先预处理
调用的时候要先对除数取mod
性能分析:

时间复杂度O(n)
适用范围:mod数是不大的素数而且多次调用,比如卢卡斯定理。
递归求逆元

1
2
3
4
5
LL inv(LL i)
{
if(i==1)return 1;
return (mod-mod/i)*inv(mod%i)%mod;
}

性能分析

时间复杂度:O(logmod)
好像找到了最简单的算法了!!

适用范围: mod数是素数,所以并不好用,比如中国剩余定理中就不好使,因为很多时候可能会忘记考虑mod数是不是素数。

miller-rabin,Pollard_rho算法

大素数判断和素因子分解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#include<iostream>
#include<algorithm>
using namespace std;


//****************************************************************
// Miller_Rabin 算法进行素数测试
//速度快,而且可以判断 <2^63的数
//****************************************************************
const int S=20;//随机算法判定次数,S越大,判错概率越小


//计算 (a*b)%c. a,b都是long long的数,直接相乘可能溢出的
// a,b,c <2^63
long long mult_mod(long long a,long long b,long long c)
{
a%=c;
b%=c;
long long ret=0;
while(b)
{
if(b&1){ret+=a;ret%=c;}
a<<=1;
if(a>=c)a%=c;
b>>=1;
}
return ret;
}



//计算 x^n %c
long long pow_mod(long long x,long long n,long long mod)//x^n%c
{
if(n==1)return x%mod;
x%=mod;
long long tmp=x;
long long ret=1;
while(n)
{
if(n&1) ret=mult_mod(ret,tmp,mod);
tmp=mult_mod(tmp,tmp,mod);
n>>=1;
}
return ret;
}





//以a为基,n-1=x*2^t a^(n-1)=1(mod n) 验证n是不是合数
//一定是合数返回true,不一定返回false
bool check(long long a,long long n,long long x,long long t)
{
long long ret=pow_mod(a,x,n);
long long last=ret;
for(int i=1;i<=t;i++)
{
ret=mult_mod(ret,ret,n);
if(ret==1&&last!=1&&last!=n-1) return true;//合数
last=ret;
}
if(ret!=1) return true;
return false;
}

// Miller_Rabin()算法素数判定
//是素数返回true.(可能是伪素数,但概率极小)
//合数返回false;

bool Miller_Rabin(long long n)
{
if(n<2)return false;
if(n==2)return true;
if((n&1)==0) return false;//偶数
long long x=n-1;
long long t=0;
while((x&1)==0){x>>=1;t++;}
for(int i=0;i<S;i++)
{
long long a=rand()%(n-1)+1;//rand()需要stdlib.h头文件
if(check(a,n,x,t))
return false;//合数
}
return true;
}


//************************************************
//pollard_rho 算法进行质因数分解
//************************************************
long long factor[100];//质因数分解结果(刚返回时是无序的)
int tol;//质因数的个数。数组小标从0开始

long long gcd(long long a,long long b)
{
if(a==0)return 1;//???????
if(a<0) return gcd(-a,b);
while(b)
{
long long t=a%b;
a=b;
b=t;
}
return a;
}

long long Pollard_rho(long long x,long long c)
{
long long i=1,k=2;
long long x0=rand()%x;
long long y=x0;
while(1)
{
i++;
x0=(mult_mod(x0,x0,x)+c)%x;
long long d=gcd(y-x0,x);
if(d!=1&&d!=x) return d;
if(y==x0) return x;
if(i==k){y=x0;k+=k;}
}
}
//对n进行素因子分解
void findfac(long long n)
{
if(Miller_Rabin(n))//素数
{
factor[tol++]=n;
return;
}
long long p=n;
while(p>=n)p=Pollard_rho(p,rand()%(n-1)+1);
findfac(p);
findfac(n/p);
}

int main()
{
//srand(time(NULL));//需要time.h头文件//POJ上G++不能加这句话
long long n;
while(scanf("%I64d",&n)!=EOF)
{
tol=0;
findfac(n);
for(int i=0;i<tol;i++)printf("%I64d ",factor[i]);
printf("\n");
if(Miller_Rabin(n))printf("Yes\n");
else printf("No\n");
}
return 0;
}

组合数学

Lucas定理

费马小定理实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include<cstring>

using namespace std;

typedef long long ll;

ll mulit(ll a,ll b,ll m){
ll ans=0;
while(b){
if(b&1) ans=(ans+a)%m;
a=(a<<1)%m;
b>>=1;
}
return ans;
}

ll quick_mod(ll a,ll b,ll m){
ll ans=1;
while(b){
if(b&1){
ans=mulit(ans,a,m);
}
a=mulit(a,a,m);
b>>=1;
}
return ans;
}

ll comp(ll a,ll b,ll m){
if(a<b) return 0;
if(a==b) return 1;
if(b>a-b) b=a-b;
ll ans=1,ca=1,cb=1;
for(int i=0;i<b;i++){
ca=ca*(a-i)%m;
cb=cb*(b-i)%m;
}
ans=ca*quick_mod(cb,m-2,m)%m;
return ans;
}

ll lucas(ll a,ll b,ll m){
ll ans=1;
while(a&&b){
ans=(ans*comp(a%m,b%m,m))%m;
a/=m;
b/=m;
}
return ans;
}

int main()
{
ll a,b,m;
while(cin>>a>>b>>m){
cout<<lucas(a,b,m)<<endl;
}
return 0;
}

exgcd实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include<cstring>

using namespace std;

typedef long long ll;

ll exgcd(ll a,ll b,ll& x,ll& y){
if(a%b==0){
x=0,y=1;
return b;
}
ll r,tx,ty;
r=exgcd(b,a%b,tx,ty);
x=ty;
y=tx-a/b*ty;
}

ll comp(ll a,ll b,ll m){
if(a<b) return 0;
if(a==b) return 1;
if(b>a-b) b=a-b;
ll ans=1,ca=1,cb=1;
for(int i=0;i<b;i++){
ca=ca*(a-i)%m;
cb=cb*(b-i)%m;
}
ll x,y;
exgcd(cb,m,x,y);
x=(x%m+m)%m;
ans=ca*x%m;
return ans;
}

ll lucas(ll a,ll b,ll m){
ll ans=1;
while(a&&b){
ans=(ans*comp(a%m,b%m,m))%m;
a/=m;
b/=m;
}
return ans;
}

int main()
{
ll a,b,m;
int n;
cin>>n;
while(n--){
cin>>a>>b>>m;
cout<<lucas(a+b,b,m)<<endl;
}
return 0;
}

全排列全组合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/**** **** **** **** **** ****
* Function Name : 全排列,全组合
**** **** **** **** **** ****/
void createper(int n) //全排列
{
int total,i,j,k,t,*a=new int[n],top;
total=1;
for(i=1; i<=n; i++)
{
a[i]=i;
total*=i;
}
for(i=1; i<n; i++)
printf("%d ",a[i]);
printf("%d\n",a[n]);
for(i=1; i<total; i++)
{
j=n;
while(a[j]<a[j-1])
j--;
k=n;
while(a[j-1]>a[k])
k--;
t=a[j-1];
a[j-1]=a[k];
a[k]=t;
top=(j+n-1)/2;
for(k=j; k<=top; k++)
{
t=a[k];
a[k]=a[n-k+j];
a[n-k+j]=t;
}
for(j=1; j<n; j++)
printf("%d ",a[j]);
printf("%d\n",a[n]);
}
}
void createfab(int m,int n) //全组合
{
int i,j,lcount,*a=new int[n+2];
for(i=1; i<=n; i++)
a[i]=i;
a[n+1]=m+1;
for(j=1; j<n; j++)
printf("%d ",a[j]);
printf("%d\n",a[n]);
lcount=1;
while(a[1]<m-n+1)
{
for(i=n; i>0; i--)
{
if(a[i]<a[i+1]-1)
{
a[i]++;
for(j=i; j<n; j++)
a[j+1]=a[j]+1;
for(j=1; j<n; j++)
printf("%d ",a[j]);
printf("%d\n",a[n]);
lcount++;
break;
}
}
}
}

母函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
using namespace std;
// Author: Tanky Woo
// www.wutianqi.com
const int _max = 10001;
// c1是保存各项质量砝码可以组合的数目
// c2是中间量,保存每一次的情况
int c1[_max], c2[_max];
int main()
{ //int n,i,j,k;
int nNum; //
int i, j, k;

while(cin >> nNum)
{
for(i=0; i<=nNum; ++i) // ---- ①
{
c1[i] = 1;
c2[i] = 0;
}
for(i=2; i<=nNum; ++i) // ----- ②
{

for(j=0; j<=nNum; ++j) // ----- ③
for(k=0; k+j<=nNum; k+=i) // ---- ④
{
c2[j+k] += c1[j];
}
for(j=0; j<=nNum; ++j) // ---- ⑤
{
c1[j] = c2[j];
c2[j] = 0;
}
}
cout << c1[nNum] << endl;
}
return 0;
}

容斥原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int p[10]={0};
int k;
void getp(int n)
{
k=0;
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
{
p[k++]=i;
}
while(n%i==0)
n/=i;
}
if(n>1) p[k++]=n;
}
int nop(int m)
{
int que[1000];
int top=0;
que[top++]=-1;
for(int i=0;i<k;i++)
{
int t=top;
for(int j=0;j<t;j++)
{
que[top++]=que[j]*p[i]*(-1);
}
}
int sum=0;
for(int i=1;i<top;i++)
{
sum+=m/que[i];
}
return sum;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
getp(n);
printf("%d\n",m-nop(m));
return 0;
}

莫比乌斯反演

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const int MAXN = 1000000;
bool check[MAXN+10];
int prime[MAXN+10];
int mu[MAXN+10];
void Moblus()
{
memset(check,false,sizeof(check));
mu[1] = 1;
int tot = 0;
for(int i = 2; i <= MAXN; i++)
{
if( !check[i] )
{
prime[tot++] = i;
mu[i] = −1;
}
for(int j = 0; j < tot; j++)
{
if(i * prime[j] > MAXN)
break;
check[i * prime[j]] = true;
if( i % prime[j] == 0)
{
mu[i * prime[j]] = 0;
break;
}
else
{
mu[i * prime[j]] = −mu[i];
}
}

莫比乌斯Euler打表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include<bits/stdc++.h>

using namespace std;

const int MAXN=1e2;

int phi[MAXN],n,tot;
int pri[MAXN];
bool mark[MAXN];

void getphi(){
phi[1]=1;
for(int i=2;i<=n;i++){
if(!mark[i]){
phi[i]=i-1;
pri[++tot]=i;
}
for(int j=1;j<=tot;j++){
int x=pri[j];
if(i*x>n) break;
mark[i*x]=1;
if(i%x==0){
phi[i*x]=phi[i]*x;
break;
}
else phi[i*x]=phi[i]*phi[x];
}
}
}

int main(){
while(~scanf("%d",&n)){
tot=0;
getphi();

printf("%d\n",phi[n]);
}
return 0;
}

离散对数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <map>
#include <set>
#include <algorithm>
using namespace std;

long long exgcd(long long a, long long b, long long &x, long long &y) {
if (!b) {x = 1; y = 0; return a;}
long long d = exgcd(b, a % b, y, x);
y -= (a / b) * x;
return d;
}

long long inv(long long a, long long n) {
long long x, y;
exgcd(a, n, x, y);
return (x + n) % n;
}

long long pow_mod(long long x, long long k, long long n) {
if (k == 0) return 1;
long long ans = pow_mod(x * x % n, k>>1, n);
if (k&1)
ans = ans * x % n;
return ans;
}

long long log_mod(long long a, long long b, long long n) {
long long m = (long long)sqrt(n + 0.5), v, e = 1, i;
v = inv(pow_mod(a, m, n), n);
map<long long, long long> x;
x[1] = 0;
for (long long i = 1; i < m; i++) {
e = e * a % n;
if (!x.count(e)) x[e] = i;
}
for (long long i = 0; i < m; i++) {
if (x.count(b)) return i * m + x[b];
b = b * v % n;
}
return -1;
}

const long long MOD = 100000007;
long long n, k, b, r, Max, x[505], y[505];
typedef pair<long long, long long> pii;

set<pii> beats;

long long cal() {
long long ans = 0;
for (long long i = 0; i < b; i++) {
if (x[i] != Max && !beats.count(make_pair(x[i] + 1, y[i])))
ans++;
}
ans += n;
for (long long i = 0; i < b; i++) if (x[i] == 1) ans--;
return pow_mod(k, ans, MOD) * pow_mod(k - 1, Max * n - b - ans, MOD) % MOD;
}

long long solve() {
long long m = cal();
if (m == r) return Max;
long long tmp = n;
for (long long i = 0; i < b; i++)
if (x[i] == Max) tmp--;
long long ans = pow_mod(k - 1, tmp, MOD) * pow_mod(k, n - tmp, MOD) % MOD;
m = m * ans % MOD;
if (m == r) return Max + 1;
return log_mod(pow_mod(k - 1, n, MOD), r * inv(m, MOD) % MOD, MOD) + Max + 1;
}

int main() {
while (~scanf("%lld%lld%lld%lld", &n, &k, &b, &r)) {
beats.clear();
Max = 1;

for (long long i = 0; i < b; i++) {
scanf("%lld%lld", &x[i], &y[i]);
beats.insert(make_pair(x[i], y[i]));
Max = max(Max, x[i]);
}
printf("%lld\n",solve());
}
return 0;
}

自适应 simpson 积分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
double simpson(double a,double b)
{
double c = a + (b−a)/2;
return (F(a) + 4*F(c) + F(b))*(b−a)/6
}
double asr(double a,double b,double eps,double A)
{
double c = a + (b−a)/2;
double L = simpson(a,c), R = simpson(c,b);
if(fabs(L + R − A) <= 15*eps)
return L + R + (L + R − A)/15.0;
return asr(a,c,eps/2,L) + asr(c,b,eps/2,R)
}
double asr(double a,double b,double eps)return asr(a,b,eps,simpson(a,b));

线性代数

快速幂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<bits/stdc++.h>
using namespace std;
int pow_mod(int a, int n, int m)
{
long long ans = 1;
while(n){
if(n&1){
ans = (ans * a) % m;
}
a = (a * a) % m;
n >>= 1;
}
return ans;
}
int main()
{
int a, n, m;
cin >> a >> n >> m;
cout << pow_mod(a, n, m);
}

矩阵快速幂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const int N=10;  
int tmp[N][N];
void multi(int a[][N],int b[][N],int n)
{
memset(tmp,0,sizeof tmp);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
tmp[i][j]+=a[i][k]*b[k][j];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
a[i][j]=tmp[i][j];
}
int res[N][N];
void Pow(int a[][N],int n)
{
memset(res,0,sizeof res);//n是幂,N是矩阵大小
for(int i=0;i<N;i++) res[i][i]=1;
while(n)
{
if(n&1)
multi(res,a,N);//res=res*a;复制直接在multi里面实现了;
multi(a,a,N);//a=a*a
n>>=1;
}
}

快速乘

如果要求模的常数是一个64bit整数,那么在做乘法时,就没有扩展类型使用,必须手写一个高精度整数运算。

O(logn)快速乘

1
2
3
4
5
6
7
8
9
inline LL quick_mul(LL a,LL n,LL m){
LL ans=0;
while(n){
if(n&1) ans=(ans+a)%m;
a=(a<<1)%m;
n>>=1;
}
return ans;
}

O(1)快速乘

1
2
3
4
5
6
7
8
typedef long long ll;
#define MOL 123456789012345LL
inline ll mul_mod_ll(ll a,ll b){
ll d=(ll)floor(a*(long double)b/MOL+0.5);
ll ret=a*b-d*MOL;
if(ret<0) ret+=MOL;
return ret;
}

首先,使用浮点数计算 ab/MOL 的值,关键在于第二句,显然 ab - d*MOL 两个乘法都可能溢出,不过没关系,因为可以预见,其差是一个64bit可以容纳的正整数,那么溢出部分的差仅可能是0或者1。最后一句符号的特判用来处理溢出部分差为1的情况。

考虑到计算 a*b/MOL 使用了浮点数计算,误差是不可避免的,故建议不要用太大的MOL使用这个方法。

模板
1
2
3
inline ll ksc(ll x,ll y,ll mod){
return (x*y-(ll)((long double)x/mod*y)*mod+mod)%mod;
}

因为x,y都是mod意义下的,保证了x*y/mod不会爆long long。

高斯消元

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**** **** **** **** **** ****
* Function Name : 高斯消元法
* Description : 求解线性方程组
*
* void exchange_col(int p1,int p2,int n)
* 交换 p1 行和 p2 行的所有数据
*
* bool gauss(int n)
* 求解系数矩阵为 n 的线性方程组,方程组无解返回 false,否则 true
*
* x1 = x0 - f(x0)/f'(x0) 牛顿迭代法
**** **** **** **** **** ****/
const int num = 100;
double matrix[num][num + 1]; //系数矩阵,从 0 开始
double ans[num]; //结果数组
void exchange_col(int p1,int p2,int n) //交换 p1 行和 p2 行的所有数据
{
double t;
int i;
for(i = 0 ; i <= n ; i++)
t = matrix[p1][i],matrix[p1][i] = matrix[p2][i],matrix[p2][i] = t;
}
bool gauss(int n) //求解系数矩阵为 n 的线性方程组
{
int i,j,k;
int p;
double r;
for(i = 0 ; i < n - 1 ; i++)
{
p = i;
for(j = i + 1 ; j < n ; j++) //寻找 i 列绝对值最大值位置
{
if(abs(matrix[j][i]) > abs(matrix[p][i]))
p = j;
}
if(p != i)
exchange_col(i,p,n);
if(matrix[i][i] == 0)
return false;
for(j = i + 1 ; j < n ; j++) //剩余列进行消元
{
r = matrix[j][i] / matrix[i][i];
for(k = i ; k <= n ; k++)
matrix[j][k] -= r * matrix[i][k];
}
}
for(i = n - 1 ; i >= 0 ; i--) //获得结果
{
ans[i] = matrix[i][n];
for(j = n - 1 ; j > i ; j--)
ans[i] -= matrix[i][j] * ans[j];
if(matrix[i][i] == 0)
return false;
ans[i] /= matrix[i][i];
}
return true;
}

字符串

字符串hash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
const int HASH = 10007;
const int MAXN = 2010;
struct HASHMAP
{
int head[HASH],next[MAXN],size;
unsigned long long state[MAXN];
int f[MAXN];
void init()
{
size = 0;
memset(head,−1,sizeof(head));
} int insert(unsigned long long val,int _id)
{
int h = val%HASH;
for(int i = head[h]; i != −1; i = next[i])
if(val == state[i])
{
int tmp = f[i];
f[i] = _id;
return tmp;
}
f[size] = _id;
state[size] = val;
next[size] = head[h];
head[h] = size++;
return 0;
}
} H;
const int SEED = 13331;
unsigned long long P[MAXN];
unsigned long long S[MAXN];
char str[MAXN];
int ans[MAXN][MAXN];
int main()
{
P[0] = 1;
for(int i = 1; i < MAXN; i++)
P[i] = P[i−1] * SEED;
int T;
scanf("%d",&T);
while(T−−)
{
scanf("%s",str);
int n = strlen(str);
S[0] = 0;
for(int i = 1; i <= n; i++)
S[i] = S[i−1]*SEED + str[i−1];
memset(ans,0,sizeof(ans));
for(int L = 1; L <= n; L++)
{
H.init();
for(int i = 1; i + L − 1 <= n; i++)
{
int l = H.insert(S[i+L−1] − S[i−1]*P[L],i);
ans[i][i+L−1] ++;
ans[l][i+L−1]−−;
}
}
for(int i = n; i >= 0; i−−)
for(int j = i; j <= n; j++)
ans[i][j] += ans[i+1][j] + ans[i][j−1] − ans[i−1];
int m,u,v;
scanf("%d",&m);
while(m−−)
{
scanf("%d%d",&u,&v);
printf("%d\n",ans[u][v]);
}
}
return 0
}

字符串和数值hash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// 整数hash
// 104729, 224737, 350377, 479909, 611953, 882377
// 1020379, 1299709, 1583539, 1870667, 2015177
// 4256233,5800079,7368787, 10570841, 15485863
const int MOD = 20023;
bool bhash[MOD];
int vhash[MOD];
int cnt[MOD];
bool find_hash(int & pos)
{
int val = pos;
pos %= MOD;
for (; bhash[pos]; pos=(pos+1)%MOD)
{
if (vhash[pos] == val)
return true;
}
return false;
}
int make_hash(int val)
{
int pos = val;
if (! find_hash(pos))
{
bhash[pos] = true;
vhash[pos] = val;
cnt[pos] = 0;
}
cnt[pos] ++;
return pos;
}
//字符串hash
const int MOD = 20023;
bool bhash[MOD];
char vhash[MOD][45];
char str[45];
int cal_str()
{
int i, j, pos;
for (i=pos=0,j=1; str[i]; i++,j=(j*27)&INT_MAX,pos&=INT_MAX)
{
int num = str[i] - 'a';
if (str[i] == ' ')
num = 26;
pos += j*num;
}
return pos % MOD;
}
bool find_hash(int & pos)
{
pos = cal_str();
for (; bhash[pos]; pos=(pos+1)%MOD)
{
if (strcmp(vhash[pos], str) == 0)
return true;
}
return false;
}
int make_hash()
{
int pos;
if (! find_hash(pos))
{
bhash[pos] = true;
strcpy(vhash[pos], str);
}
return pos;
}

BM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
int* CreateBC(char* pattern, int len)
{
int* bc = new int[256];

for(int i = 0; i < 256; ++i)
{
bc[i] = -1;
}

for(int i = 0; i < len; ++i)
{
bc[pattern[i]] = i;
}

for(int i = 0; i < 256; ++i)
{
if(bc[i] != -1)
{
cout << "bc[" << i << "] = " << bc[i] << endl;
}
}
return bc;
}

int* CreateSuffix(char* pattern, int len)
{
int* suffix = new int[len];
suffix[len - 1] = len;

for(int i = len - 2; i >= 0; --i)
{
int j = i;
for(; pattern[j] == pattern[len - 1 - i + j] && j >= 0; --j);
suffix[i] = i - j;
}

for(int i = 0; i < len; ++i)
{
cout << "suffix[" << i << "] = " << suffix[i] << endl;
}

return suffix;
}

int* CreateGS(char* pattern, int len)
{
int* suffix = CreateSuffix(pattern, len);
int* gs = new int[len];
/*
在计算gs数组时,从移动数最大的情况依次到移动数最少的情况赋值,
确保在合理的移动范围内,移动最少的距离,避免失配的情况。
*/

//第三种情况
for(int i = 1; i < len; ++i)
{
gs[i] = len;
}

//第二种情况
for(int i = len - 1; i >= 0; --i) //从右往左扫描,确保模式串移动最少。
{
if(suffix[i] == i + 1) //是一个与好后缀匹配的最大前缀
{
for(int j = 0; j < len - 1 - i; ++j)
{
if(gs[j] == len) //gs[j]初始值为len, 这样确保gs[j]只被修改一次
{
gs[j] = len - 1 - i;
}
}
}
}

//第一种情况
for(int i = 0; i < len - 1; ++i)
{
gs[len - 1 - suffix[i]] = len - 1 - i;
}

return gs;
}

int bm_search(char* text, int text_len, char* pattern, int pattern_len)
{
int* bc = CreateBC(pattern, pattern_len);
int* gs = CreateGS(pattern, pattern_len);

for(int i = 0; i <= text_len - pattern_len; )
{
int j = pattern_len - 1;
for(; j >= 0 && pattern[j] == text[i+j]; --j);

if(j < 0)
{
return i;
}

int bad_char_index = j;
char bad_char = text[i + j];

int bc_move = bad_char_index - bc[bad_char];
if(bc_move < 0)
{
bc_move = bad_char_index + 1;
}

int gs_move = gs[bad_char_index];

int move = (bc_move > gs_move ? bc_move : gs_move);

i += move;
}

if(bc != NULL)
{
delete bc;
bc = NULL;
}

if(gs != NULL)
{
delete bc;
gs = NULL;
}
return -1;
}

KMP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**** **** **** **** **** ****
* Function Name : 字符串匹配(KMP 算法)
* Description : O(N+M)
**** **** **** **** **** ****/
void get_nextval(const string & s, int * p)
{
int i = 0,j = -1;
p[0] = -1;
while(i < s.size())
{
if(j == -1 || s[i] == s[j])
{
++i,++j;
if(s[i] != s[j])
p[i] = j;
else
p[i] = p[j];
}
else
j = p[j];
}
}
int Index_KMP(const string & s, const string & s1, int pos)
{
int i = pos - 1,j = 0;
int * next = new int[s1.size()];
get_nextval(s1,next);
while(i <= s.size() && j <= s1.size())
{
if(j == -1 || s[i] == s1[j])
++i,++j;
else
j = next[j];
}
if(j > s1.size())
return i - s1.size();
else
return -1;
}

AC自动机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//该程序不能判别相同模式串,因此若模式串重复,答案会将相同模式串当做不同的处理,因此若需要可以用map去重或修改insert
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int maxm=500006; //maxm是总结点数:约为字母数+++

char s[1000005],word[55];
int nxt[maxm][26],tail[maxm],f[maxm],size; //nxt是结点指向不同字母的结点下标,tail是表示该结点为几个单词的词尾(可能需要计算重复的模式串情况),f是当不匹配时转跳到的结点下标,size是结点数

int newnode(){ //初始化整个trie或建立新的结点时,首先初始化当前结点所指向的26个字母的结点为0,表示暂时还没有指向的字母,然后暂定该结点不是单词尾结点,暂无失配时转跳位置(即转跳到根节点),返回结点标号
memset(nxt[size],0,sizeof(nxt[size]));
f[size]=tail[size]=0;
return size++;
}

void insert(char s[]){ //构造trie,p为当前结点的上一个结点标号,初始为0;x即为当前结点(上个结点标号指向当前字母的结点)标号,若此结点还未出现过,那么就建立这个结点;然后更新p为当前结点标号以便后续操作
int i,p=0;
for(i=0;s[i];i++){
int &x=nxt[p][s[i]-'a'];
p=x?x:x=newnode();
}
tail[p]++; //此时仅将s串记录,即将s串结尾的结点加1,若无相同模式串,则此操作只会使所有串尾结点的tail值由0变为1,但有相同模式串,则会重复记录,需要去重可以用map或用tail[p]=1;语句来完成
}

void makenxt(){ //利用bfs来构造失配指针
int i;
queue<int>q;
f[0]=0; //先将0结点挂的字母加入队列,失配指针指向0结点
for(i=0;i<26;i++){
int v=nxt[0][i];
if(v){
f[v]=0;
q.push(v);
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(i=0;i<26;i++){
int v=nxt[u][i];
if(!v)nxt[u][i]=nxt[f[u]][i]; //当u结点没有i对应字母,则视为失配,将其指向失配后转跳到的结点所指向的i对应字母
else{
q.push(v); //u结点存在指向i的结点,则将所指向的结点下标加入队列
f[v]=nxt[f[u]][i]; //失配指针指向上个结点失配指针指向结点所挂当前字母的结点
}
}
}
}

int query(char s[]){ //查询s串中模式串出现了多少种/次
int ans=0,v=0;
for(int i=0;s[i];i++){
while(v&&!nxt[v][s[i]-'a'])v=f[v]; //先匹配直到没有失配
v=nxt[v][s[i]-'a'];
int tmp=v;
while(tmp){
ans+=tail[tmp];
tail[tmp]=0; //这里加这句是为了仅计算出现多少种模式链,而若不加这句则可以计算累计出现多少次
tmp=f[tmp];
}
}
return ans;
}

int main(){
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
size=0,newnode();
for(int i=0;i<n;i++){
scanf("%s",word);
insert(word);
}
makenxt();
scanf("%s",s);
printf("%d\n",query(s));
}
return 0;
}

后缀自动机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
const int CHAR = 26;
const int MAXN = 250010;
struct SAM_Node
{
SAM_Node *fa,*next[CHAR];
int len;
long long cnt;
void clear()
{
fa = 0;
memset(next,0,sizeof(next));
cnt = 0;
}
} pool[MAXN*2];
SAM_Node *root,*tail;
SAM_Node* newnode(int len)
{
SAM_Node* cur = tail++;
cur−>clear();
cur−>len = len;
return cur;
}
void SAM_init()
{
tail = pool;
root = newnode(0);
}
SAM_Node* extend(SAM_Node* last,int x)
{
SAM_Node *p = last, *np = newnode(p−>len+1);
while(p && !p−>next[x])
p−>next[x] = np, p = p−>fa;
if(!p)
np−>fa = root;
else
{
SAM_Node* q = p−>next[x];
if(q−>len == p−>len+1)
np−>fa = q;
else
{
SAM_Node* nq = newnode(p−>len+1);
memcpy(nq−>next,q−>next,sizeof(q−>nextnq−>fa = q−>fa; q−>fa = np−>fa = nq;
while(p && p−>next[x] == q)p−>next[x] = nq, p = p−>fa;
}
}
return np;
}

计算几何

基础计算几何

几何公式

三角形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
\1. 半周长 P=(a+b+c)/2

\2. 面积 S=aHa/2=absin(C)/2=sqrt(P(P-a)(P-b)(P-c))

\3. 中线 Ma=sqrt(2(b^2+c^2)-a^2)/2=sqrt(b^2+c^2+2bccos(A))/2

\4. 角平分线 Ta=sqrt(bc((b+c)^2-a^2))/(b+c)=2bccos(A/2)/(b+c)

\5. 高线 Ha=bsin(C)=csin(B)=sqrt(b^2-((a^2+b^2-c^2)/(2a))^2)

\6. 内切圆半径 r=S/P=asin(B/2)sin(C/2)/sin((B+C)/2)

=4Rsin(A/2)sin(B/2)sin(C/2)=sqrt((P-a)(P-b)(P-c)/P)

=Ptan(A/2)tan(B/2)tan(C/2)

\7. 外接圆半径 R=abc/(4S)=a/(2sin(A))=b/(2sin(B))=c/(2sin(C))

四边形

1
2
3
4
5
6
7
8
9
10
11
D1,D2为对角线,M对角线中点连线,A为对角线夹角

\1. a^2+b^2+c^2+d^2=D1^2+D2^2+4M^2

\2. S=D1D2sin(A)/2

(以下对圆的内接四边形)

\3. ac+bd=D1D2

\4. S=sqrt((P-a)(P-b)(P-c)(P-d)),P为半周长

正n边形

1
2
3
4
5
6
7
8
9
R为外接圆半径,r为内切圆半径

\1. 中心角 A=2PI/n

\2. 内角 C=(n-2)PI/n

\3. 边长 a=2sqrt(R^2-r^2)=2Rsin(A/2)=2rtan(A/2)

\4. 面积 S=nar/2=nr^2tan(A/2)=nR^2sin(A)/2=na^2/(4tan(A/2))

1
2
3
4
5
6
7
8
9
\1. 弧长 l=rA

\2. 弦长 a=2sqrt(2hr-h^2)=2rsin(A/2)

\3. 弓形高 h=r-sqrt(r^2-a^2/4)=r(1-cos(A/2))=atan(A/4)/2

\4. 扇形面积 S1=rl/2=r^2A/2

\5. 弓形面积 S2=(rl-a(r-h))/2=r^2(A-sin(A))/2

棱柱

1
2
3
4
5
\1. 体积 V=Ah,A为底面积,h为高

\2. 侧面积 S=lp,l为棱长,p为直截面周长

\3. 全面积 T=S+2A

棱锥

1
2
3
4
5
6
7
\1. 体积 V=Ah/3,A为底面积,h为高

(以下对正棱锥)

\2. 侧面积 S=lp/2,l为斜高,p为底面周长

\3. 全面积 T=S+A

棱台

1
2
3
4
5
6
7
\1. 体积 V=(A1+A2+sqrt(A1A2))h/3,A1.A2为上下底面积,h为高

(以下为正棱台)

\2. 侧面积 S=(p1+p2)l/2,p1.p2为上下底面周长,l为斜高

\3. 全面积 T=S+A1+A2

圆柱

1
2
3
4
5
\1. 侧面积 S=2PIrh

\2. 全面积 T=2PIr(h+r)

\3. 体积 V=PIr^2h

圆锥

1
2
3
4
5
6
7
\1. 母线 l=sqrt(h^2+r^2)

\2. 侧面积 S=PIrl

\3. 全面积 T=PIr(l+r)

\4. 体积 V=PIr^2h/3

圆台

1
2
3
4
5
6
7
\1. 母线 l=sqrt(h^2+(r1-r2)^2)

\2. 侧面积 S=PI(r1+r2)l

\3. 全面积 T=PIr1(l+r1)+PIr2(l+r2)

\4. 体积 V=PI(r1^2+r2^2+r1r2)h/3

1
2
3
\1. 全面积 T=4PIr^2

\2. 体积 V=4PIr^3/3

球台

1
2
3
4
5
\1. 侧面积 S=2PIrh

\2. 全面积 T=PI(2rh+r1^2+r2^2)

\3. 体积 V=PIh(3(r1^2+r2^2)+h^2)/6

球扇形

1
2
3
\1. 全面积 T=PIr(2h+r0),h为球冠高,r0为球冠底面半径

\2. 体积 V=2PIr^2h/3

直线与线段

预备函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
**//结构定义与宏定义**

\#include<stdio.h>

\#include<string.h>

\#include<stdlib.h>

\#include <math.h>

\#define eps 1e-8

\#define zero(x) (((x)>0?(x):-(x))<eps)

struct point

{

​ double x,y;

};

struct line

{

​ point a,b;

};



**//计算cross product (P1-P0)x(P2-P0)**

double xmult(point p1,point p2,point p0)

{

​ return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);

}

double xmult(double x1,double y1,double x2,double y2,double x0,double y0)

{

​ return (x1-x0)*(y2-y0)-(x2-x0)*(y1-y0);

}



**//计算dot product (P1-P0).(P2-P0)**

double dmult(point p1,point p2,point p0)

{

​ return (p1.x-p0.x)*(p2.x-p0.x)+(p1.y-p0.y)*(p2.y-p0.y);

}

double dmult(double x1,double y1,double x2,double y2,double x0,double y0)

{

​ return (x1-x0)*(x2-x0)+(y1-y0)*(y2-y0);

}



**//两点距离**

double distance(point p1,point p2)

{

​ return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));

}

double distance(double x1,double y1,double x2,double y2)

{

​ return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));

}

判三点是否共线

1
2
3
4
5
6
7
int dots_inline(point p1,point p2,point p3)

{

return zero(xmult(p1,p2,p3));

}

判点是否在线段上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
**//判点是否在线段上,包括端点(下面为两种接口模式)**

int dot_online_in(point p,line l)

{

return zero(xmult(p,l.a,l.b))&&(l.a.x-p.x)*(l.b.x-p.x)<eps&&(l.a.y-p.y)*(l.b.y-p.y)<eps;

}

int dot_online_in(point p,point l1,point l2)

{

return zero(xmult(p,l1,l2))&&(l1.x-p.x)*(l2.x-p.x)<eps&&(l1.y-p.y)*(l2.y-p.y)<eps;

}

**//判点是否在线段上,不包括端点**

int dot_online_ex(point p,line l)

{

return dot_online_in(p,l)&&(!zero(p.x-l.a.x)||!zero(p.y-l.a.y))

&&(!zero(p.x-l.b.x)||!zero(p.y-l.b.y));

}

判断两点在线段的同一侧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
**//判两点在线段同侧,点在线段上返回0**

int same_side(point p1,point p2,line l)

{

return xmult(l.a,p1,l.b)*xmult(l.a,p2,l.b)>eps;

}

int same_side(point p1,point p2,point l1,point l2)

{

return xmult(l1,p1,l2)*xmult(l1,p2,l2)>eps;

}

判断两点是否在线段的异侧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
**//判两点在线段异侧,点在线段上返回0**

int opposite_side(point p1,point p2,line l)

{

return xmult(l.a,p1,l.b)*xmult(l.a,p2,l.b)<-eps;

}

int opposite_side(point p1,point p2,point l1,point l2)

{

return xmult(l1,p1,l2)*xmult(l1,p2,l2)<-eps;

}

求点关于直线的对称点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
**// 点关于直线的对称点 // by lyt**

**// 缺点:用了斜率**

**// 也可以利用"点到直线上的最近点"来做,避免使用斜率。**

point symmetric_point(point p1, point l1, point l2)

{

point ret;

if (l1.x > l2.x - eps && l1.x < l2.x + eps)

{

ret.x = (2 * l1.x - p1.x);

ret.y = p1.y;

}

else

{

double k = (l1.y - l2.y ) / (l1.x - l2.x);

ret.x = (2*k*k*l1.x + 2*k*p1.y - 2*k*l1.y - k*k*p1.x + p1.x) / (1 + k*k);

ret.y = p1.y - (ret.x - p1.x ) / k;

}

return ret;

}

判断两线段是否相交

常用版
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//定义点

struct Point

{

double x;

double y;

};

typedef struct Point point;



//叉积

double multi(point p0, point p1, point p2)

{

return ( p1.x - p0.x )*( p2.y - p0.y )-( p2.x - p0.x )*( p1.y - p0.y );

}





//相交返回true,否则为false, 接口为两线段的端点

bool isIntersected(point s1,point e1, point s2,point e2)

{

return (max(s1.x,e1.x) >= min(s2.x,e2.x)) &&

(max(s2.x,e2.x) >= min(s1.x,e1.x)) &&

(max(s1.y,e1.y) >= min(s2.y,e2.y)) &&

(max(s2.y,e2.y) >= min(s1.y,e1.y)) &&

(multi(s1,s2,e1)*multi(s1,e1,e2)>0) &&

(multi(s2,s1,e2)*multi(s2,e2,e1)>0);

}
不常用版
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
**//判两线段相交,包括端点和部分重合**

int intersect_in(line u,line v)

{

if (!dots_inline(u.a,u.b,v.a)||!dots_inline(u.a,u.b,v.b))

return !same_side(u.a,u.b,v)&&!same_side(v.a,v.b,u);

return dot_online_in(u.a,v)||dot_online_in(u.b,v)||dot_online_in(v.a,u)||dot_online_in(v.b,u);

}

int intersect_in(point u1,point u2,point v1,point v2)

{

if (!dots_inline(u1,u2,v1)||!dots_inline(u1,u2,v2))

return !same_side(u1,u2,v1,v2)&&!same_side(v1,v2,u1,u2);

return dot_online_in(u1,v1,v2)||dot_online_in(u2,v1,v2)||dot_online_in(v1,u1,u2)||dot_online_in(v2,u1,u2);

}



**//判两线段相交,不包括端点和部分重合**

int intersect_ex(line u,line v)

{

return opposite_side(u.a,u.b,v)&&opposite_side(v.a,v.b,u);

}

int intersect_ex(point u1,point u2,point v1,point v2)

{

return opposite_side(u1,u2,v1,v2)&&opposite_side(v1,v2,u1,u2);

}

求两条直线的交点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
**//计算两直线交点,注意事先判断直线是否平行!**

**//线段交点请另外判线段相交(同时还是要判断是否平行!)**

point intersection(point u1,point u2,point v1,point v2)

{

point ret=u1;

double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x))

/((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));

ret.x+=(u2.x-u1.x)*t;

ret.y+=(u2.y-u1.y)*t;

return ret;

}

点到直线的最近距离

1
2
3
4
5
6
7
8
9
10
11
point ptoline(point p,point l1,point l2)

{

point t=p;

t.x+=l1.y-l2.y,t.y+=l2.x-l1.x;

return intersection(p,t,l1,l2);

}

点到线段的最近距离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
point ptoseg(point p,point l1,point l2)

{

point t=p;

t.x+=l1.y-l2.y,t.y+=l2.x-l1.x;

if (xmult(l1,t,p)*xmult(l2,t,p)>eps)

return distance(p,l1)<distance(p,l2)?l1:l2;

return intersection(p,t,l1,l2);

}

多边形

预备浮点函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
\#include <stdlib.h>

\#include<stdio.h>

\#include<string.h>

\#include <math.h>

\#define MAXN 1000



**//offset为多变形坐标的最大绝对值**

\#define offset 10000

\#define eps 1e-8



**//浮点数判0**

\#define zero(x) (((x)>0?(x):-(x))<eps)



**//浮点数判断符**

\#define _sign(x) ((x)>eps?1:((x)<-eps?2:0))



**//定义点**

struct point

{

double x,y;

}pt[MAXN ];



**//定义线段**

struct line

{

point a,b;

};



**//叉积**

double xmult(point p1,point p2,point p0)

{

return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);

}

判定是否是凸多边形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
**//判定凸多边形,顶点按顺时针或逆时针给出,允许相邻边共线,是凸多边形返回1,否则返回0**

int is_convex(int n,point* p)

{

int i,s[3]={1,1,1};

for (i=0;i<n&&s[1]|s[2];i++)

s[_sign(xmult(p[(i+1)%n],p[(i+2)%n],p[i]))]=0;

return s[1]|s[2];

}



**//判凸行,顶点按顺时针或逆时针给出,不允许相邻边共线,是凸多边形返回1,否则返回0**

int is_convex_v2(int n,point* p)

{

int i,s[3]={1,1,1};

for (i=0;i<n&&s[0]&&s[1]|s[2];i++)

s[_sign(xmult(p[(i+1)%n],p[(i+2)%n],p[i]))]=0;

return s[0]&&s[1]|s[2];

}

判定点是否在多边形内

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
**//判点在凸多边形内或多边形边上时返回1,严格在凸多边形外返回0**

int inside_convex(point q,int n,point* p)

{

int i,s[3]={1,1,1};

for (i=0;i<n&&s[1]|s[2];i++)

s[_sign(xmult(p[(i+1)%n],q,p[i]))]=0;

return s[1]|s[2];

}



**//判点严格在凸多边形内返回1,在边上或者严格在外返回0**

int inside_convex_v2(point q,int n,point* p)

{

int i,s[3]={1,1,1};

for (i=0;i<n&&s[0]&&s[1]|s[2];i++)

s[_sign(xmult(p[(i+1)%n],q,p[i]))]=0;

return s[0]&&s[1]|s[2];

}



**//判点在任意多边形内,顶点按顺时针或逆时针给出**

**//on_edge表示点在多边形边上时的返回值, offset为多边形坐标上限,严格在内返回1,严格在外返回0**

int inside_polygon(point q,int n,point* p,int on_edge=2)

{

point q2;

int i=0,count;

while (i<n)

for (count=i=0,q2.x=rand()+offset,q2.y=rand()+offset;i<n;i++)

{

if (zero(xmult(q,p[i],p[(i+1)%n]))&&(p[i].x-q.x)*(p[(i+1)%n].x-q.x)<eps

&&(p[i].y-q.y)*(p[(i+1)%n].y-q.y)<eps)

return on_edge;



else if (zero(xmult(q,q2,p[i])))

break;



else if (xmult(q,p[i],q2)*xmult(q,p[(i+1)%n],q2)<-eps&&

xmult(p[i],q,p[(i+1)%n])*xmult(p[i],q2,p[(i+1)%n])<-eps)

count++;

}

return count&1;

}

判定一条线段是否在一个任意多边形内

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
**//预备函数**

inline int opposite_side(point p1,point p2,point l1,point l2)

{

return xmult(l1,p1,l2)*xmult(l1,p2,l2)<-eps;

}

inline int dot_online_in(point p,point l1,point l2)

{

return zero(xmult(p,l1,l2))&&(l1.x-p.x)*(l2.x-p.x)<eps&&(l1.y-p.y)*(l2.y-p.y)<eps;

}



**//判线段在任意多边形内,顶点按顺时针或逆时针给出,与边界相交返回1**

int inside_polygon(point l1,point l2,int n,point* p)

{

point t[MAXN],tt;

int i,j,k=0;

if (!inside_polygon(l1,n,p)||!inside_polygon(l2,n,p))

return 0;

for (i=0;i<n;i++)

{

if (opposite_side(l1,l2,p[i],p[(i+1)%n])&&opposite_side(p[i],p[(i+1)%n],l1,l2))

return 0;

else if (dot_online_in(l1,p[i],p[(i+1)%n]))

t[k++]=l1;

else if (dot_online_in(l2,p[i],p[(i+1)%n]))

t[k++]=l2;

else if (dot_online_in(p[i],l1,l2))

t[k++]=p[i];

}

for (i=0;i<k;i++)

for (j=i+1;j<k;j++)

{

tt.x=(t[i].x+t[j].x)/2;

tt.y=(t[i].y+t[j].y)/2;

if (!inside_polygon(tt,n,p))

return 0;

}

return 1;

}

三角形

预备函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
\#include <math.h>

\#include <string.h>

\#include <stdlib.h>

\#include<stdio.h>

**//定义点**

struct point

{

double x,y;

};

typedef struct point point;



**//定义直线**

struct line

{

point a,b;

};

typedef struct line line;

**//两点距离**

double distance(point p1,point p2)

{

return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));

}

**//两直线求交点**

point intersection(line u,line v)

{

point ret=u.a;

double t=((u.a.x-v.a.x)*(v.a.y-v.b.y)-(u.a.y-v.a.y)*(v.a.x-v.b.x))

/((u.a.x-u.b.x)*(v.a.y-v.b.y)-(u.a.y-u.b.y)*(v.a.x-v.b.x));

ret.x+=(u.b.x-u.a.x)*t;

ret.y+=(u.b.y-u.a.y)*t;

return ret;

}

求三角形的外心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
point circumcenter(point a,point b,point c)

{

line u,v;

u.a.x=(a.x+b.x)/2;

u.a.y=(a.y+b.y)/2;

u.b.x=u.a.x-a.y+b.y;

u.b.y=u.a.y+a.x-b.x;

v.a.x=(a.x+c.x)/2;

v.a.y=(a.y+c.y)/2;

v.b.x=v.a.x-a.y+c.y;

v.b.y=v.a.y+a.x-c.x;

return intersection(u,v);

}

求三角形内心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
point incenter(point a,point b,point c)

{

line u,v;

double m,n;

u.a=a;

m=atan2(b.y-a.y,b.x-a.x);

n=atan2(c.y-a.y,c.x-a.x);

u.b.x=u.a.x+cos((m+n)/2);

u.b.y=u.a.y+sin((m+n)/2);

v.a=b;

m=atan2(a.y-b.y,a.x-b.x);

n=atan2(c.y-b.y,c.x-b.x);

v.b.x=v.a.x+cos((m+n)/2);

v.b.y=v.a.y+sin((m+n)/2);

return intersection(u,v);

}

求三角形垂心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
point perpencenter(point a,point b,point c)

{

line u,v;

u.a=c;

u.b.x=u.a.x-a.y+b.y;

u.b.y=u.a.y+a.x-b.x;

v.a=b;

v.b.x=v.a.x-a.y+c.y;

v.b.y=v.a.y+a.x-c.x;

return intersection(u,v);

}

预备函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
\#include <math.h>

\#include <stdlib.h>

\#include <stdio.h>

\#include <string.h>

\#define eps 1e-8

struct point

{

double x,y;

};

typedef struct point point;

double xmult(point p1,point p2,point p0)

{

return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);

}

double distance(point p1,point p2)

{

return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));

}

**//点到直线的距离**

double disptoline(point p,point l1,point l2)

{

return fabs(xmult(p,l1,l2))/distance(l1,l2);

}

**//求两直线交点**

point intersection(point u1,point u2,point v1,point v2)

{

point ret=u1;

double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x))

/((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));

ret.x+=(u2.x-u1.x)*t;

ret.y+=(u2.y-u1.y)*t;

return ret;

}

判定直线是否与圆相交

1
2
3
4
5
6
7
8
9
//判直线和圆相交,包括相切

int intersect_line_circle(point c,double r,point l1,point l2)

{

return disptoline(c,l1,l2)<r+eps;

}

判定线段与圆相交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int intersect_seg_circle(point c,double r, point l1,point l2)

{

double t1=distance(c,l1)-r,t2=distance(c,l2)-r;

point t=c;

if (t1<eps||t2<eps)

return t1>-eps||t2>-eps;

t.x+=l1.y-l2.y;

t.y+=l2.x-l1.x;

return xmult(l1,c,t)*xmult(l2,c,t)<eps&&disptoline(c,l1,l2)-r<eps;

}

判圆和圆相交

1
2
3
4
5
6
7
int intersect_circle_circle(point c1,double r1,point c2,double r2)

{

return distance(c1,c2)<r1+r2+eps&&distance(c1,c2)>fabs(r1-r2)-eps;

}

计算圆上到点p最近点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**//当p为圆心时,返回圆心本身**

point dot_to_circle(point c,double r,point p)

{

point u,v;

if (distance(p,c)<eps)

return p;

u.x=c.x+r*fabs(c.x-p.x)/distance(c,p);

u.y=c.y+r*fabs(c.y-p.y)/distance(c,p)*((c.x-p.x)*(c.y-p.y)<0?-1:1);

v.x=c.x-r*fabs(c.x-p.x)/distance(c,p);

v.y=c.y-r*fabs(c.y-p.y)/distance(c,p)*((c.x-p.x)*(c.y-p.y)<0?-1:1);

return distance(u,p)<distance(v,p)?u:v;

}

计算直线与圆的交点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
**//计算直线与圆的交点,保证直线与圆有交点**

**//计算线段与圆的交点可用这个函数后判点是否在线段上**

void intersection_line_circle(point c,double r,point l1,point l2,point& p1,point& p2)

{

point p=c;

double t;

p.x+=l1.y-l2.y;

p.y+=l2.x-l1.x;

p=intersection(p,c,l1,l2);

t=sqrt(r*r-distance(p,c)*distance(p,c))/distance(l1,l2);

p1.x=p.x+(l2.x-l1.x)*t;

p1.y=p.y+(l2.y-l1.y)*t;

p2.x=p.x-(l2.x-l1.x)*t;

p2.y=p.y-(l2.y-l1.y)*t;

}

计算两个圆的交点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**//计算圆与圆的交点,保证圆与圆有交点,圆心不重合**

void intersection_circle_circle(point c1,double r1,point c2,double r2,point& p1,point& p2)

{

point u,v;

double t;

t=(1+(r1*r1-r2*r2)/distance(c1,c2)/distance(c1,c2))/2;

u.x=c1.x+(c2.x-c1.x)*t;

u.y=c1.y+(c2.y-c1.y)*t;

v.x=u.x+c1.y-c2.y;

v.y=u.y-c1.x+c2.x;

intersection_line_circle(c1,r1,u,v,p1,p2);

}

球面

给出地球经度纬度,计算圆心角

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
\#include <math.h>

const double pi=acos(-1);



**//计算圆心角lat表示纬度,-90<=w<=90,lng表示经度**

**//返回两点所在大圆劣弧对应圆心角,0<=angle<=pi**

double angle(double lng1,double lat1,double lng2,double lat2)

{

double dlng=fabs(lng1-lng2)*pi/180;

while (dlng>=pi+pi)

dlng-=pi+pi;

if (dlng>pi)

dlng=pi+pi-dlng;

lat1*=pi/180,lat2*=pi/180;

return acos(cos(lat1)*cos(lat2)*cos(dlng)+sin(lat1)*sin(lat2));

}

已知经纬度,计算地球上两点直线距离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
**//计算距离,r为球半径**

double line_dist(double r,double lng1,double lat1,double lng2,double lat2)

{

double dlng=fabs(lng1-lng2)*pi/180;

while (dlng>=pi+pi)

dlng-=pi+pi;

if (dlng>pi)

dlng=pi+pi-dlng;

lat1*=pi/180,lat2*=pi/180;

return r*sqrt(2-2*(cos(lat1)*cos(lat2)*cos(dlng)+sin(lat1)*sin(lat2)));

}

已知经纬度,计算地球上两点球面距离

1
2
3
4
5
6
7
8
9
**//计算球面距离,r为球半径**

inline double sphere_dist(double r,double lng1,double lat1,double lng2,double lat2)

{

return r*angle(lng1,lat1,lng2,lat2);

}

三维几何的若干模板

预备函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
**//三维几何函数库**

\#include <math.h>

\#define eps 1e-8

\#define zero(x) (((x)>0?(x):-(x))<eps)

struct point3{double x,y,z;};

struct line3{point3 a,b;};

struct plane3{point3 a,b,c;};



**//计算cross product U x V**

point3 xmult(point3 u,point3 v){

point3 ret;

ret.x=u.y*v.z-v.y*u.z;

ret.y=u.z*v.x-u.x*v.z;

ret.z=u.x*v.y-u.y*v.x;

return ret;

}



**//计算dot product U . V**

double dmult(point3 u,point3 v){

return u.x*v.x+u.y*v.y+u.z*v.z;

}



**//矢量差 U - V**

point3 subt(point3 u,point3 v){

point3 ret;

ret.x=u.x-v.x;

ret.y=u.y-v.y;

ret.z=u.z-v.z;

return ret;

}



**//取平面法向量**

point3 pvec(plane3 s){

return xmult(subt(s.a,s.b),subt(s.b,s.c));

}

point3 pvec(point3 s1,point3 s2,point3 s3){

return xmult(subt(s1,s2),subt(s2,s3));

}



**//两点距离,单参数取向量大小**

double distance(point3 p1,point3 p2){

return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)+(p1.z-p2.z)*(p1.z-p2.z));

}



**//向量大小**

double vlen(point3 p){

return sqrt(p.x*p.x+p.y*p.y+p.z*p.z);

}

判定三点是否共线

//判三点共线

1
2
3
4
5
int dots_inline(point3 p1,point3 p2,point3 p3){

return vlen(xmult(subt(p1,p2),subt(p2,p3)))<eps;

}

判定四点是否共面

1
2
3
4
5
6
7
**//判四点共面**

int dots_onplane(point3 a,point3 b,point3 c,point3 d){

return zero(dmult(pvec(a,b,c),subt(d,a)));

}

判定点是否在线段上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
**//判点是否在线段上,包括端点和共线**

int dot_online_in(point3 p,line3 l){

return zero(vlen(xmult(subt(p,l.a),subt(p,l.b))))&&(l.a.x-p.x)*(l.b.x-p.x)<eps&&

(l.a.y-p.y)*(l.b.y-p.y)<eps&&(l.a.z-p.z)*(l.b.z-p.z)<eps;

}

int dot_online_in(point3 p,point3 l1,point3 l2){

return zero(vlen(xmult(subt(p,l1),subt(p,l2))))&&(l1.x-p.x)*(l2.x-p.x)<eps&&

(l1.y-p.y)*(l2.y-p.y)<eps&&(l1.z-p.z)*(l2.z-p.z)<eps;

}



**//判点是否在线段上,不包括端点**

int dot_online_ex(point3 p,line3 l){

return dot_online_in(p,l)&&(!zero(p.x-l.a.x)||!zero(p.y-l.a.y)||!zero(p.z-l.a.z))&&

(!zero(p.x-l.b.x)||!zero(p.y-l.b.y)||!zero(p.z-l.b.z));

}

int dot_online_ex(point3 p,point3 l1,point3 l2){

return dot_online_in(p,l1,l2)&&(!zero(p.x-l1.x)||!zero(p.y-l1.y)||!zero(p.z-l1.z))&&

(!zero(p.x-l2.x)||!zero(p.y-l2.y)||!zero(p.z-l2.z));

}

判断点是否在空间三角形上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
**//判点是否在空间三角形上,包括边界,三点共线无意义**

int dot_inplane_in(point3 p,plane3 s){

return zero(vlen(xmult(subt(s.a,s.b),subt(s.a,s.c)))-vlen(xmult(subt(p,s.a),subt(p,s.b)))-

vlen(xmult(subt(p,s.b),subt(p,s.c)))-vlen(xmult(subt(p,s.c),subt(p,s.a))));

}

int dot_inplane_in(point3 p,point3 s1,point3 s2,point3 s3){

return zero(vlen(xmult(subt(s1,s2),subt(s1,s3)))-vlen(xmult(subt(p,s1),subt(p,s2)))-

vlen(xmult(subt(p,s2),subt(p,s3)))-vlen(xmult(subt(p,s3),subt(p,s1))));

}





**//判点是否在空间三角形上,不包括边界,三点共线无意义**

int dot_inplane_ex(point3 p,plane3 s){

return dot_inplane_in(p,s)&&vlen(xmult(subt(p,s.a),subt(p,s.b)))>eps&&

vlen(xmult(subt(p,s.b),subt(p,s.c)))>eps&&vlen(xmult(subt(p,s.c),subt(p,s.a)))>eps;

}

int dot_inplane_ex(point3 p,point3 s1,point3 s2,point3 s3){

return dot_inplane_in(p,s1,s2,s3)&&vlen(xmult(subt(p,s1),subt(p,s2)))>eps&&

vlen(xmult(subt(p,s2),subt(p,s3)))>eps&&vlen(xmult(subt(p,s3),subt(p,s1)))>eps;

}

判断两点是否在线段同侧

1
2
3
4
5
6
7
8
9
10
11
12
13
**//判两点在线段同侧,点在线段上返回0,不共面无意义**

int same_side(point3 p1,point3 p2,line3 l){

return dmult(xmult(subt(l.a,l.b),subt(p1,l.b)),xmult(subt(l.a,l.b),subt(p2,l.b)))>eps;

}

int same_side(point3 p1,point3 p2,point3 l1,point3 l2){

return dmult(xmult(subt(l1,l2),subt(p1,l2)),xmult(subt(l1,l2),subt(p2,l2)))>eps;

}

判断两点是否在线段异侧

1
2
3
4
5
6
7
8
9
10
11
12
13
**//判两点在线段异侧,点在线段上返回0,不共面无意义**

int opposite_side(point3 p1,point3 p2,line3 l){

return dmult(xmult(subt(l.a,l.b),subt(p1,l.b)),xmult(subt(l.a,l.b),subt(p2,l.b)))<-eps;

}

int opposite_side(point3 p1,point3 p2,point3 l1,point3 l2){

return dmult(xmult(subt(l1,l2),subt(p1,l2)),xmult(subt(l1,l2),subt(p2,l2)))<-eps;

}

判断两点是否在平面同侧

1
2
3
4
5
6
7
8
9
10
11
12
13
**//判两点在平面同侧,点在平面上返回0**

int same_side(point3 p1,point3 p2,plane3 s){

return dmult(pvec(s),subt(p1,s.a))*dmult(pvec(s),subt(p2,s.a))>eps;

}

int same_side(point3 p1,point3 p2,point3 s1,point3 s2,point3 s3){

return dmult(pvec(s1,s2,s3),subt(p1,s1))*dmult(pvec(s1,s2,s3),subt(p2,s1))>eps;

}

判断两点是否在平面异侧

1
2
3
4
5
6
7
8
9
10
11
12
13
**//判两点在平面异侧,点在平面上返回0**

int opposite_side(point3 p1,point3 p2,plane3 s){

return dmult(pvec(s),subt(p1,s.a))*dmult(pvec(s),subt(p2,s.a))<-eps;

}

int opposite_side(point3 p1,point3 p2,point3 s1,point3 s2,point3 s3){

return dmult(pvec(s1,s2,s3),subt(p1,s1))*dmult(pvec(s1,s2,s3),subt(p2,s1))<-eps;

}

判断两空间直线是否平行

1
2
3
4
5
6
7
8
9
10
11
12
13
**//判两直线平行**

int parallel(line3 u,line3 v){

return vlen(xmult(subt(u.a,u.b),subt(v.a,v.b)))<eps;

}

int parallel(point3 u1,point3 u2,point3 v1,point3 v2){

return vlen(xmult(subt(u1,u2),subt(v1,v2)))<eps;

}

判断两平面是否平行

1
2
3
4
5
6
7
8
9
10
11
12
13
**//判两平面平行**

int parallel(plane3 u,plane3 v){

return vlen(xmult(pvec(u),pvec(v)))<eps;

}

int parallel(point3 u1,point3 u2,point3 u3,point3 v1,point3 v2,point3 v3){

return vlen(xmult(pvec(u1,u2,u3),pvec(v1,v2,v3)))<eps;

}

判断直线是否与平面平行

1
2
3
4
5
6
7
8
9
10
11
12
13
**//判直线与平面平行**

int parallel(line3 l,plane3 s){

return zero(dmult(subt(l.a,l.b),pvec(s)));

}

int parallel(point3 l1,point3 l2,point3 s1,point3 s2,point3 s3){

return zero(dmult(subt(l1,l2),pvec(s1,s2,s3)));

}

判断两直线是否垂直

1
2
3
4
5
6
7
8
9
10
11
12
13
**//判两直线垂直**

int perpendicular(line3 u,line3 v){

return zero(dmult(subt(u.a,u.b),subt(v.a,v.b)));

}

int perpendicular(point3 u1,point3 u2,point3 v1,point3 v2){

return zero(dmult(subt(u1,u2),subt(v1,v2)));

}

判断两平面是否垂直

1
2
3
4
5
6
7
8
9
10
11
12
13
//判两平面垂直

int perpendicular(plane3 u,plane3 v){

return zero(dmult(pvec(u),pvec(v)));

}

int perpendicular(point3 u1,point3 u2,point3 u3,point3 v1,point3 v2,point3 v3){

return zero(dmult(pvec(u1,u2,u3),pvec(v1,v2,v3)));

}

判断两条空间线段是否相交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
**//判两线段相交,包括端点和部分重合**

int intersect_in(line3 u,line3 v){

if (!dots_onplane(u.a,u.b,v.a,v.b))

return 0;

if (!dots_inline(u.a,u.b,v.a)||!dots_inline(u.a,u.b,v.b))

return !same_side(u.a,u.b,v)&&!same_side(v.a,v.b,u);

return dot_online_in(u.a,v)||dot_online_in(u.b,v)||dot_online_in(v.a,u)||dot_online_in(v.b,u);

}

int intersect_in(point3 u1,point3 u2,point3 v1,point3 v2){

if (!dots_onplane(u1,u2,v1,v2))

return 0;

if (!dots_inline(u1,u2,v1)||!dots_inline(u1,u2,v2))

return !same_side(u1,u2,v1,v2)&&!same_side(v1,v2,u1,u2);

return dot_online_in(u1,v1,v2)||dot_online_in(u2,v1,v2)||dot_online_in(v1,u1,u2)||dot_online_in(v2,u1,u2);

}



**//判两线段相交,不包括端点和部分重合**

int intersect_ex(line3 u,line3 v){

return dots_onplane(u.a,u.b,v.a,v.b)&&opposite_side(u.a,u.b,v)&&opposite_side(v.a,v.b,u);

}

int intersect_ex(point3 u1,point3 u2,point3 v1,point3 v2){

return dots_onplane(u1,u2,v1,v2)&&opposite_side(u1,u2,v1,v2)&&opposite_side(v1,v2,u1,u2);

}

判断线段是否与空间三角形相交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
**//判线段与空间三角形相交,包括交于边界和(部分)包含**

int intersect_in(line3 l,plane3 s){

return !same_side(l.a,l.b,s)&&!same_side(s.a,s.b,l.a,l.b,s.c)&&

!same_side(s.b,s.c,l.a,l.b,s.a)&&!same_side(s.c,s.a,l.a,l.b,s.b);

}

int intersect_in(point3 l1,point3 l2,point3 s1,point3 s2,point3 s3){

return !same_side(l1,l2,s1,s2,s3)&&!same_side(s1,s2,l1,l2,s3)&&

!same_side(s2,s3,l1,l2,s1)&&!same_side(s3,s1,l1,l2,s2);

}



**//判线段与空间三角形相交,不包括交于边界和(部分)包含**

int intersect_ex(line3 l,plane3 s){

return opposite_side(l.a,l.b,s)&&opposite_side(s.a,s.b,l.a,l.b,s.c)&&

opposite_side(s.b,s.c,l.a,l.b,s.a)&&opposite_side(s.c,s.a,l.a,l.b,s.b);

}

int intersect_ex(point3 l1,point3 l2,point3 s1,point3 s2,point3 s3){

return opposite_side(l1,l2,s1,s2,s3)&&opposite_side(s1,s2,l1,l2,s3)&&

opposite_side(s2,s3,l1,l2,s1)&&opposite_side(s3,s1,l1,l2,s2);

}

计算两条直线的交点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
**//计算两直线交点,注意事先判断直线是否共面和平行!**

**//线段交点请另外判线段相交(同时还是要判断是否平行!)**

point3 intersection(line3 u,line3 v){

point3 ret=u.a;

double t=((u.a.x-v.a.x)*(v.a.y-v.b.y)-(u.a.y-v.a.y)*(v.a.x-v.b.x))

/((u.a.x-u.b.x)*(v.a.y-v.b.y)-(u.a.y-u.b.y)*(v.a.x-v.b.x));

ret.x+=(u.b.x-u.a.x)*t;

ret.y+=(u.b.y-u.a.y)*t;

ret.z+=(u.b.z-u.a.z)*t;

return ret;

}

point3 intersection(point3 u1,point3 u2,point3 v1,point3 v2){

point3 ret=u1;

double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x))

/((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));

ret.x+=(u2.x-u1.x)*t;

ret.y+=(u2.y-u1.y)*t;

ret.z+=(u2.z-u1.z)*t;

return ret;

}

计算直线与平面的交点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
**//计算直线与平面交点,注意事先判断是否平行,并保证三点不共线!**

**//线段和空间三角形交点请另外判断**

point3 intersection(line3 l,plane3 s){

point3 ret=pvec(s);

double t=(ret.x*(s.a.x-l.a.x)+ret.y*(s.a.y-l.a.y)+ret.z*(s.a.z-l.a.z))/

(ret.x*(l.b.x-l.a.x)+ret.y*(l.b.y-l.a.y)+ret.z*(l.b.z-l.a.z));

ret.x=l.a.x+(l.b.x-l.a.x)*t;

ret.y=l.a.y+(l.b.y-l.a.y)*t;

ret.z=l.a.z+(l.b.z-l.a.z)*t;

return ret;

}

point3 intersection(point3 l1,point3 l2,point3 s1,point3 s2,point3 s3){

point3 ret=pvec(s1,s2,s3);

double t=(ret.x*(s1.x-l1.x)+ret.y*(s1.y-l1.y)+ret.z*(s1.z-l1.z))/

(ret.x*(l2.x-l1.x)+ret.y*(l2.y-l1.y)+ret.z*(l2.z-l1.z));

ret.x=l1.x+(l2.x-l1.x)*t;

ret.y=l1.y+(l2.y-l1.y)*t;

ret.z=l1.z+(l2.z-l1.z)*t;

return ret;

}

计算两平面的交线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
**//计算两平面交线,注意事先判断是否平行,并保证三点不共线!**

line3 intersection(plane3 u,plane3 v){

line3 ret;

ret.a=parallel(v.a,v.b,u.a,u.b,u.c)?intersection(v.b,v.c,u.a,u.b,u.c):intersection(v.a,v.b,u.a,u.b,u.c);

ret.b=parallel(v.c,v.a,u.a,u.b,u.c)?intersection(v.b,v.c,u.a,u.b,u.c):intersection(v.c,v.a,u.a,u.b,u.c);

return ret;

}

line3 intersection(point3 u1,point3 u2,point3 u3,point3 v1,point3 v2,point3 v3){

line3 ret;

ret.a=parallel(v1,v2,u1,u2,u3)?intersection(v2,v3,u1,u2,u3):intersection(v1,v2,u1,u2,u3);

ret.b=parallel(v3,v1,u1,u2,u3)?intersection(v2,v3,u1,u2,u3):intersection(v3,v1,u1,u2,u3);

return ret;

}

点到直线的距离

1
2
3
4
5
6
7
8
9
10
11
12
13
**//点到直线距离**

double ptoline(point3 p,line3 l){

return vlen(xmult(subt(p,l.a),subt(l.b,l.a)))/distance(l.a,l.b);

}

double ptoline(point3 p,point3 l1,point3 l2){

return vlen(xmult(subt(p,l1),subt(l2,l1)))/distance(l1,l2);

}

计算点到平面的距离

1
2
3
4
5
6
7
8
9
10
11
12
13
**//点到平面距离**

double ptoplane(point3 p,plane3 s){

return fabs(dmult(pvec(s),subt(p,s.a)))/vlen(pvec(s));

}

double ptoplane(point3 p,point3 s1,point3 s2,point3 s3){

return fabs(dmult(pvec(s1,s2,s3),subt(p,s1)))/vlen(pvec(s1,s2,s3));

}

计算直线到直线的距离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
**//直线到直线距离**

double linetoline(line3 u,line3 v){

point3 n=xmult(subt(u.a,u.b),subt(v.a,v.b));

return fabs(dmult(subt(u.a,v.a),n))/vlen(n);

}

double linetoline(point3 u1,point3 u2,point3 v1,point3 v2){

point3 n=xmult(subt(u1,u2),subt(v1,v2));

return fabs(dmult(subt(u1,v1),n))/vlen(n);

}

空间两直线夹角的cos值

1
2
3
4
5
6
7
8
9
10
11
12
13
**//两直线夹角cos值**

double angle_cos(line3 u,line3 v){

return dmult(subt(u.a,u.b),subt(v.a,v.b))/vlen(subt(u.a,u.b))/vlen(subt(v.a,v.b));

}

double angle_cos(point3 u1,point3 u2,point3 v1,point3 v2){

return dmult(subt(u1,u2),subt(v1,v2))/vlen(subt(u1,u2))/vlen(subt(v1,v2));

}

两平面夹角的cos值

1
2
3
4
5
6
7
8
9
10
11
12
13
**//两平面夹角cos值**

double angle_cos(plane3 u,plane3 v){

return dmult(pvec(u),pvec(v))/vlen(pvec(u))/vlen(pvec(v));

}

double angle_cos(point3 u1,point3 u2,point3 u3,point3 v1,point3 v2,point3 v3){

return dmult(pvec(u1,u2,u3),pvec(v1,v2,v3))/vlen(pvec(u1,u2,u3))/vlen(pvec(v1,v2,v3));

}

直线与平面夹角sin值

1
2
3
4
5
6
7
8
9
10
11
12
13
//直线平面夹角sin值

double angle_sin(line3 l,plane3 s){

return dmult(subt(l.a,l.b),pvec(s))/vlen(subt(l.a,l.b))/vlen(pvec(s));

}

double angle_sin(point3 l1,point3 l2,point3 s1,point3 s2,point3 s3){

return dmult(subt(l1,l2),pvec(s1,s2,s3))/vlen(subt(l1,l2))/vlen(pvec(s1,s2,s3));

}

高级计算几何

最远曼哈顿距离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
\#include <stdio.h>

\#define INF 9999999999999.0

struct Point

{

double x[5];

}pt[100005];

double dis[32][100005], coe[5], minx[32], maxx[32];

**//去掉绝对值后有2^D种可能**

void GetD(int N, int D)

{

int s, i, j, tot=(1<<D);

for (s=0;s<tot;s++)

{

for (i=0;i<D;i++)

if (s&(1<<i))

coe[i]=-1.0;

else coe[i]=1.0;

for (i=0;i<N;i++)

{

dis[s][i]=0.0;

for (j=0;j<D;j++)

dis[s][i]=dis[s][i]+coe[j]*pt[i].x[j];

}

}

}

**//取每种可能中的最大差距**

void Solve(int N, int D)

{

int s, i, tot=(1<<D);

double tmp, ans;

for (s=0;s<tot;s++)

{

minx[s]=INF;

maxx[s]=-INF;

for (i=0; i<N; i++)

{

if (minx[s]>dis[s][i]) minx[s]=dis[s][i];

if (maxx[s]<dis[s][i]) maxx[s]=dis[s][i];

}

}

ans=0.0;

for (s=0; s<tot; s++)

{

tmp=maxx[s]-minx[s];

if (tmp>ans) ans=tmp;

}

printf("%.2lf\n", ans);

}

int main (void)

{

int n, i;

while (scanf("%d",&n)==1)

{

for (i=0;i<n;i++)

scanf("%lf%lf%lf%lf%lf",&pt[i].x[0],&pt[i].x[1],&pt[i].x[2],&pt[i].x[3],&pt[i].x[4]);

GetD(n, 5);

Solve(n, 5);

}

return 0;

}

最近点对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
\#include <stdio.h>

\#include <math.h>

\#include <stdlib.h>

\#define Max(x,y) (x)>(y)?(x):(y)

struct Q

{

double x, y;

}q[100001], sl[10], sr[10];



int cntl, cntr, lm, rm;

double ans;



int cmp(const void*p1, const void*p2)

{

struct Q*a1=(struct Q*)p1;

struct Q*a2=(struct Q*)p2;

if (a1->x<a2->x)return -1;

else if (a1->x==a2->x)return 0;

else return 1;

}



double CalDis(double x1, double y1, double x2, double y2)

{

return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));

}



void MinDis(int l, int r)

{

if (l==r) return;

double dis;

if (l+1==r)

{

dis=CalDis(q[l].x,q[l].y,q[r].x,q[r].y);

if (ans>dis) ans=dis;

return;

}

int mid=(l+r)>>1, i, j;

MinDis(l,mid);

MinDis(mid+1,r);



lm=mid+1-5;

if (lm<l) lm=l;

rm=mid+5;

if (rm>r) rm=r;



cntl=cntr=0;

for (i=mid;i>=lm;i--)

{

if (q[mid+1].x-q[i].x>=ans)break;

sl[++cntl]=q[i];

}

for (i=mid+1;i<=rm;i++)

{

if (q[i].x-q[mid].x>=ans)break;

sr[++cntr]=q[i];

}



for (i=1;i<=cntl;i++)

for (j=1;j<=cntr;j++)

{

dis=CalDis(sl[i].x,sl[i].y,sr[j].x,sr[j].y);

if (dis<ans) ans=dis;

}

}



int main (void)

{

int n, i;

while (scanf("%d",&n)==1&&n)

{

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

scanf("%lf %lf", &q[i].x,&q[i].y);

qsort(q+1,n,sizeof(struct Q),cmp);

ans=CalDis(q[1].x,q[1].y,q[2].x,q[2].y);

MinDis(1,n);

printf("%.2lf\n",ans/2.0);

}

return 0;

}

最小包围圆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
\#include<stdio.h>

\#include<string.h>

\#include<math.h>

struct Point

{

double x;

double y;

}pt[1005];

struct Traingle

{

struct Point p[3];

};

struct Circle

{

struct Point center;

double r;

}ans;

**//计算两点距离**

double Dis(struct Point p, struct Point q)

{

double dx=p.x-q.x;

double dy=p.y-q.y;

return sqrt(dx*dx+dy*dy);

}

**//计算三角形面积**

double Area(struct Traingle ct)

{

return fabs((ct.p[1].x-ct.p[0].x)*(ct.p[2].y-ct.p[0].y)-(ct.p[2].x-ct.p[0].x)*(ct.p[1].y-ct.p[0].y))/2.0;

}

**//求三角形的外接圆,返回圆心和半径(存在结构体"圆"中)**

struct Circle CircumCircle(struct Traingle t)

{

struct Circle tmp;

double a, b, c, c1, c2;

double xA, yA, xB, yB, xC, yC;

a = Dis(t.p[0], t.p[1]);

b = Dis(t.p[1], t.p[2]);

c = Dis(t.p[2], t.p[0]);

//根据S = a * b * c / R / 4;求半径R

tmp.r = (a*b*c)/(Area(t)*4.0);

xA = t.p[0].x;

yA = t.p[0].y;

xB = t.p[1].x;

yB = t.p[1].y;

xC = t.p[2].x;

yC = t.p[2].y;

c1 = (xA*xA+yA*yA - xB*xB-yB*yB) / 2;

c2 = (xA*xA+yA*yA - xC*xC-yC*yC) / 2;

tmp.center.x = (c1*(yA - yC)-c2*(yA - yB)) / ((xA - xB)*(yA - yC)-(xA - xC)*(yA - yB));

tmp.center.y = (c1*(xA - xC)-c2*(xA - xB)) / ((yA - yB)*(xA - xC)-(yA - yC)*(xA - xB));

return tmp;

}

**//确定最小包围圆**

struct Circle MinCircle(int num, struct Traingle ct)

{

struct Circle ret;

if (num==0) ret.r = 0.0;

else if (num==1)

{

ret.center = ct.p[0];

ret.r = 0.0;

}

else if (num==2)

{

ret.center.x = (ct.p[0].x+ct.p[1].x)/2.0;

ret.center.y = (ct.p[0].y+ct.p[1].y)/2.0;

ret.r = Dis(ct.p[0], ct.p[1])/2.0;

}

else if(num==3) ret = CircumCircle(ct);

return ret;

}

**//递归实现增量算法**

void Dfs(int x, int num, struct Traingle ct)

{

int i, j;

struct Point tmp;

ans = MinCircle(num, ct);

if (num==3) return;

for (i=1; i<=x; i++)

if (Dis(pt[i], ans.center)>ans.r)

{

ct.p[num]=pt[i];

Dfs(i-1, num+1, ct);

tmp=pt[i];

for (j=i;j>=2;j--)

pt[j]=pt[j-1];

pt[1]=tmp;

}

}

void Solve(int n)

{

struct Traingle ct;

Dfs(n, 0, ct);

}

int main (void)

{

int n, i;

while (scanf("%d", &n)!=EOF && n)

{

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

scanf("%lf %lf", &pt[i].x, &pt[i].y);

Solve(n);

printf("%.2lf %.2lf %.2lf\n", ans.center.x, ans.center.y, ans.r);

}

return 0;

}

求两个圆的交点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
\#include<stdio.h>

\#include<string.h>

\#include<math.h>

\#include<stdlib.h>

const double eps = 1e-8;

const double PI = acos(-1.0);



struct Point

{

double x;

double y;

};

typedef struct Point point;



struct Line

{

double s, t;

};

typedef struct Line Line;



struct Circle

{

Point center;

double r;

Line line[505];

int cnt;

bool covered;



}circle[105];



double distance(point p1, point p2)

{

double dx = p1.x-p2.x;

double dy = p1.y-p2.y;

return sqrt(dx*dx + dy*dy);

}



point intersection(point u1,point u2, point v1,point v2)

{

point ret = u1;

double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x)) /

((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));

ret.x += (u2.x-u1.x)*t;

ret.y += (u2.y-u1.y)*t;

return ret;

}



void intersection_line_circle(point c,double r,point l1,point l2,point& p1,point& p2)

{

point p=c;

double t;

p.x+=l1.y-l2.y;

p.y+=l2.x-l1.x;

p=intersection(p,c,l1,l2);

t=sqrt(r*r-distance(p,c)*distance(p,c))/distance(l1,l2);

p1.x=p.x+(l2.x-l1.x)*t;

p1.y=p.y+(l2.y-l1.y)*t;

p2.x=p.x-(l2.x-l1.x)*t;

p2.y=p.y-(l2.y-l1.y)*t;

}



**//计算圆与圆的交点,保证圆与圆有交点,圆心不重合**

void intersection_circle_circle(point c1,double r1,point c2,double r2,point& p1,point& p2)

{

point u,v;

double t;

t=(1+(r1*r1-r2*r2)/distance(c1,c2)/distance(c1,c2))/2;

u.x=c1.x+(c2.x-c1.x)*t;

u.y=c1.y+(c2.y-c1.y)*t;

v.x=u.x+c1.y-c2.y;

v.y=u.y-c1.x+c2.x;

intersection_line_circle(c1,r1,u,v,p1,p2);

}

求三角形外接圆圆心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
struct Point

{

double x;

double y;

}pt[1005];

struct Traingle

{

struct Point p[3];

};

struct Circle

{

struct Point center;

double r;

**}**ans;

**//计算两点距离**

double Dis(struct Point p, struct Point q)

{

double dx=p.x-q.x;

double dy=p.y-q.y;

return sqrt(dx*dx+dy*dy);

}

**//计算三角形面积**

double Area(struct Traingle ct)

{

return fabs((ct.p[1].x-ct.p[0].x)*(ct.p[2].y-ct.p[0].y)-(ct.p[2].x-ct.p[0].x)*(ct.p[1].y-ct.p[0].y))/2.0;

}

**//求三角形的外接圆,返回圆心和半径(存在结构体"圆"中)**

struct Circle CircumCircle(struct Traingle t)

{

struct Circle tmp;

double a, b, c, c1, c2;

double xA, yA, xB, yB, xC, yC;

a = Dis(t.p[0], t.p[1]);

b = Dis(t.p[1], t.p[2]);

c = Dis(t.p[2], t.p[0]);

//根据S = a * b * c / R / 4;求半径R

tmp.r = (a*b*c)/(Area(t)*4.0);

xA = t.p[0].x;

yA = t.p[0].y;

xB = t.p[1].x;

yB = t.p[1].y;

xC = t.p[2].x;

yC = t.p[2].y;

c1 = (xA*xA+yA*yA - xB*xB-yB*yB) / 2;

c2 = (xA*xA+yA*yA - xC*xC-yC*yC) / 2;

tmp.center.x = (c1*(yA - yC)-c2*(yA - yB)) / ((xA - xB)*(yA - yC)-(xA - xC)*(yA - yB));

tmp.center.y = (c1*(xA - xC)-c2*(xA - xB)) / ((yA - yB)*(xA - xC)-(yA - yC)*(xA - xB));

return tmp;

}

求凸包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
\#include <stdio.h>

\#include <string.h>

\#include <stdlib.h>

\#include <math.h>

\#define INF 999999999.9

\#define PI acos(-1.0)

struct Point

{

double x, y, dis;

}pt[1005], stack[1005], p0;

int top, tot;

**//计算几何距离**

double Dis(double x1, double y1, double x2, double y2)

{

return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));

}

**//极角比较, 返回-1: p0p1在p0p2的右侧,返回0:p0,p1,p2共线**

int Cmp_PolarAngel(struct Point p1, struct Point p2, struct Point pb)

{

double delta=(p1.x-pb.x)*(p2.y-pb.y)-(p2.x-pb.x)*(p1.y-pb.y);

if (delta<0.0) return 1;

else if (delta==0.0) return 0;

else return -1;

}

**// 判断向量p2p3是否对p1p2构成左旋**

bool Is_LeftTurn(struct Point p3, struct Point p2, struct Point p1)

{

int type=Cmp_PolarAngel(p3, p1, p2);

if (type<0) return true;

return false;

}

**//先按极角排,再按距离由小到大排**

int Cmp(const void*p1, const void*p2)

{

struct Point*a1=(struct Point*)p1;

struct Point*a2=(struct Point*)p2;

int type=Cmp_PolarAngel(*a1, *a2, p0);

if (type<0) return -1;

else if (type==0)

{

if (a1->dis<a2->dis) return -1;

else if (a1->dis==a2->dis) return 0;

else return 1;

}

else return 1;

}

**//求凸包**

void Solve(int n)

{

int i, k;

p0.x=p0.y=INF;

for (i=0;i<n;i++)

{

scanf("%lf %lf",&pt[i].x, &pt[i].y);

if (pt[i].y < p0.y)

{

p0.y=pt[i].y;

p0.x=pt[i].x;

k=i;

}

else if (pt[i].y==p0.y)

{

if (pt[i].x<p0.x)

{

p0.x=pt[i].x;

k=i;

}

}

}

pt[k]=pt[0];

pt[0]=p0;

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

pt[i].dis=Dis(pt[i].x,pt[i].y, p0.x,p0.y);

qsort(pt+1, n-1, sizeof(struct Point), Cmp);

**//去掉极角相同的点**

tot=1;

for (i=2;i<n;i++)

if (Cmp_PolarAngel(pt[i], pt[i-1], p0))

pt[tot++]=pt[i-1];

pt[tot++]=pt[n-1];

**//求凸包**

top=1;

stack[0]=pt[0];

stack[1]=pt[1];

for (i=2;i<tot;i++)

{

while (top>=1 && Is_LeftTurn(pt[i], stack[top], stack[top-1])==false)

top--;

stack[++top]=pt[i];

}

}

int main (void)

{

int n;

while (scanf("%d",&n)==2)

{

Solve(n);

}

return 0;

}

凸包卡壳旋转求出所有对踵点、最远点对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
\#include <stdio.h>

\#include <string.h>

\#include <stdlib.h>

\#include <math.h>

\#define INF 999999999.9

\#define PI acos(-1.0)

struct Point

{

double x, y, dis;

}pt[6005], stack[6005], p0;

int top, tot;

**//计算几何距离**

double Dis(double x1, double y1, double x2, double y2)

{

return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));

}

**//极角比较, 返回-1: p0p1在p0p2的右侧,返回0:p0,p1,p2共线**

int Cmp_PolarAngel(struct Point p1, struct Point p2, struct Point pb)

{

double delta=(p1.x-pb.x)*(p2.y-pb.y)-(p2.x-pb.x)*(p1.y-pb.y);

if (delta<0.0) return 1;

else if (delta==0.0) return 0;

else return -1;

}

**// 判断向量p2p3是否对p1p2构成左旋**

bool Is_LeftTurn(struct Point p3, struct Point p2, struct Point p1)

{

int type=Cmp_PolarAngel(p3, p1, p2);

if (type<0) return true;

return false;

}

**//先按极角排,再按距离由小到大排**

int Cmp(const void*p1, const void*p2)

{

struct Point*a1=(struct Point*)p1;

struct Point*a2=(struct Point*)p2;

int type=Cmp_PolarAngel(*a1, *a2, p0);

if (type<0) return -1;

else if (type==0)

{

if (a1->dis<a2->dis) return -1;

else if (a1->dis==a2->dis) return 0;

else return 1;

}

else return 1;

}

**//求凸包**

void Hull(int n)

{

int i, k;

p0.x=p0.y=INF;

for (i=0;i<n;i++)

{

scanf("%lf %lf",&pt[i].x, &pt[i].y);

if (pt[i].y < p0.y)

{

p0.y=pt[i].y;

p0.x=pt[i].x;

k=i;

}

else if (pt[i].y==p0.y)

{

if (pt[i].x<p0.x)

{

p0.x=pt[i].x;

k=i;

}

}

}

pt[k]=pt[0];

pt[0]=p0;

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

pt[i].dis=Dis(pt[i].x,pt[i].y, p0.x,p0.y);

qsort(pt+1, n-1, sizeof(struct Point), Cmp);

**//去掉极角相同的点**

tot=1;

for (i=2;i<n;i++)

if (Cmp_PolarAngel(pt[i], pt[i-1], p0))

pt[tot++]=pt[i-1];

pt[tot++]=pt[n-1];

**//求凸包**

top=1;

stack[0]=pt[0];

stack[1]=pt[1];

for (i=2;i<tot;i++)

{

while (top>=1 && Is_LeftTurn(pt[i], stack[top], stack[top-1])==false)

top--;

stack[++top]=pt[i];

}

}

**//计算叉积**

double CrossProduct(struct Point p1, struct Point p2, struct Point p3)

{

return (p1.x-p3.x)*(p2.y-p3.y)-(p2.x-p3.x)*(p1.y-p3.y);

**}**

**//卡壳旋转,求出凸多边形所有对踵点**

void Rotate(struct Point*ch, int n)

{

int i, p=1;

double t1, t2, ans=0.0, dif;

ch[n]=ch[0];

for (i=0;i<n;i++)

{

**//如果下一个点与当前边构成的三角形的面积更大,则说明此时不构成对踵点**

while (fabs(CrossProduct(ch[i],ch[i+1],ch[p+1])) > fabs(CrossProduct(ch[i],ch[i+1],ch[p])))

p=(p+1)%n;

dif=fabs(CrossProduct(ch[i],ch[i+1],ch[p+1])) - fabs(CrossProduct(ch[i],ch[i+1],ch[p]));

**//如果当前点和下一个点分别构成的三角形面积相等,则说明两条边即为平行线,对角线两端都可能是对踵点**

if (dif==0.0)

{

t1=Dis(ch[p].x, ch[p].y, ch[i].x, ch[i].y);

t2=Dis(ch[p+1].x, ch[p+1].y, ch[i+1].x, ch[i+1].y);

if (t1>ans)ans=t1;

if (t2>ans)ans=t2;

}

**//说明p,i是对踵点**

else if (dif<0.0)

{

t1=Dis(ch[p].x, ch[p].y, ch[i].x, ch[i].y);

if (t1>ans)ans=t1;

}

}

printf("%.2lf\n",ans);

}

int main (void)

{

int n;

while (scanf("%d",&n)==1)

{

Hull(n);

Rotate(stack, top+1);

}

return 0;

}

凸包+旋转卡壳求平面面积最大三角

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
\#include <stdio.h>

\#include <string.h>

\#include <stdlib.h>

\#include <math.h>

\#define INF 99999999999.9

\#define PI acos(-1.0)

struct Point

{

double x, y, dis;

}pt[50005], stack[50005], p0;

int top, tot;

double Dis(double x1, double y1, double x2, double y2)

{

return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));

}

int Cmp_PolarAngel(struct Point p1, struct Point p2, struct Point pb)

{

double delta=(p1.x-pb.x)*(p2.y-pb.y)-(p2.x-pb.x)*(p1.y-pb.y);

if (delta<0.0) return 1;

else if (delta==0.0) return 0;

else return -1;

}

bool Is_LeftTurn(struct Point p3, struct Point p2, struct Point p1)

{

int type=Cmp_PolarAngel(p3, p1, p2);

if (type<0) return true;

return false;

}

int Cmp(const void*p1, const void*p2)

{

struct Point*a1=(struct Point*)p1;

struct Point*a2=(struct Point*)p2;

int type=Cmp_PolarAngel(*a1, *a2, p0);

if (type<0) return -1;

else if (type==0)

{

if (a1->dis<a2->dis) return -1;

else if (a1->dis==a2->dis) return 0;

else return 1;

}

else return 1;

}

void Hull(int n)

{

int i, k;

p0.x=p0.y=INF;

for (i=0;i<n;i++)

{

scanf("%lf %lf",&pt[i].x, &pt[i].y);

if (pt[i].y < p0.y)

{

p0.y=pt[i].y;

p0.x=pt[i].x;

k=i;

}

else if (pt[i].y==p0.y)

{

if (pt[i].x<p0.x)

{

p0.x=pt[i].x;

k=i;

}

}

}

pt[k]=pt[0];

pt[0]=p0;

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

pt[i].dis=Dis(pt[i].x,pt[i].y, p0.x,p0.y);

qsort(pt+1, n-1, sizeof(struct Point), Cmp);

tot=1;

for (i=2;i<n;i++)

if (Cmp_PolarAngel(pt[i], pt[i-1], p0))

pt[tot++]=pt[i-1];

pt[tot++]=pt[n-1];

top=1;

stack[0]=pt[0];

stack[1]=pt[1];

for (i=2;i<tot;i++)

{

while (top>=1 && Is_LeftTurn(pt[i], stack[top], stack[top-1])==false)

top--;

stack[++top]=pt[i];

}

}

double TArea(struct Point p1, struct Point p2, struct Point p3)

{

return fabs((p1.x-p3.x)*(p2.y-p3.y)-(p2.x-p3.x)*(p1.y-p3.y));

}

void Rotate(struct Point*ch, int n)

{

if (n<3)

{

printf("0.00\n");

return;

}

int i, j, k;

double ans=0.0, tmp;

ch[n]=ch[0];

for (i=0;i<n;i++)

{

j=(i+1)%n;

k=(j+1)%n;

while ((j!=k) && (k!=i))

{

while (TArea(ch[i],ch[j],ch[k+1])>TArea(ch[i],ch[j],ch[k]))

k=(k+1)%n;

tmp=TArea(ch[i],ch[j], ch[k]);

if (tmp>ans) ans=tmp;

j=(j+1)%n;

}

}

printf("%.2lf\n",ans/2.0);

}

int main (void)

{

int n;

while (scanf("%d",&n)==1)

{

if (n==-1)break;

Hull(n);

Rotate(stack, top+1);

}

return 0;

}

Pick定理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
**// Pick定理求整点多边形内部整点数目**

**// (1) 给定顶点座标均是整点(或正方形格点)的简单多边形,皮克定理说明了其面积A和内部格点数目i、边上格点数目b的关系:A = i + b/2 - 1;**

**// (2) 在两点(x1,y1),(x2,y2)连线之间的整点个数(包含一个端点)为:gcd(|x1-x2|,|y1-y2|);**

**// (3) 求三角形面积用叉乘**



\#include<stdio.h>

\#include<stdlib.h>

\#include<math.h>

\#include<string.h>



long long x[3], y[3], area, b;

long long My_Abs(long long t)

{

if (t<0) return -t;

return t;

}

long long Gcd(long long x, long long y)

{

if (y==0) return x;

long long mod=x%y;

while (mod)

{

x=y;

y=mod;

mod=x%y;

}

return y;

}

int main (void)

{

int i;

while (1)

{

for (i = 0;i < 3;i ++)

scanf("%lld %lld", &x[i], &y[i]);

if(x[0]==0&&y[0]==0&&x[1]==0&&y[1]==0&&x[2]==0&&y[2]==0) break;

area = (x[1]-x[0])*(y[2]-y[0])-(x[2]-x[0])*(y[1]-y[0]);

area = My_Abs(area);

b=0;

b=Gcd(My_Abs(x[1]-x[0]), My_Abs(y[1]-y[0])) + Gcd(My_Abs(x[2]-x[0]), My_Abs(y[2]-y[0])) + Gcd(My_Abs(x[1]-x[2]), My_Abs(y[1]-y[2]));

printf("%lld\n", (area-b+2)/2);

}

return 0;

}

求多边形面积和重心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
\#include <stdio.h>

\#include <math.h>

int x[1000003], y[1000003];

double A, tx, ty, tmp;

int main (void)

{

int cases, n, i;

scanf ("%d", &cases);

while (cases --)

{

scanf ("%d", &n);

A = 0.0;

x[0] = y[0] = 0;

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

{

scanf ("%d %d", &x[i], &y[i]);

A += (x[i-1]*y[i] - x[i]*y[i-1]);

}

A += x[n]*y[1] - x[1]*y[n];

A = A / 2.0;

tx = ty = 0.0;

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

{

tmp = x[i]*y[i+1] - x[i+1]*y[i];

tx += (x[i]+x[i+1]) * tmp;

ty += (y[i]+y[i+1]) * tmp;

}

tmp = x[n]*y[1] - x[1]*y[n];

tx += (x[n]+x[1])*tmp;

ty += (y[n]+y[1])*tmp;

printf ("%.2lf %.2lf\n", tx/(6.0*A), ty/(6.0*A));

}

return 0;

}

判断一个简单多边形是否有核

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
\#include <stdio.h>

\#include <string.h>

const int INF = (1<<30);

struct Point

{

int x, y;

}pt[150];

typedef struct Point Point;

bool turn_right[150];

int det(Point s1, Point t1, Point s2, Point t2)

{

int d1x = t1.x-s1.x;

int d1y = t1.y-s1.y;



int d2x = t2.x-s2.x;

int d2y = t2.y-s2.y;



return d1x*d2y - d2x*d1y;

}

void Swap(int &a, int &b)

{

if (a>b)

{

int t=a;

a=b;

b=t;

}

}

int main (void)

{

int n, i, cross, maxx, minx, maxy, miny, maxn, minn, countn=0;

while (scanf("%d", &n)==1&&n)

{

maxx=maxy=-INF;

minx=miny=INF;

**//点按顺时针给出**

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

{

scanf("%d %d", &pt[i].x, &pt[i].y);

if (maxx<pt[i].x) maxx=pt[i].x;

if (maxy<pt[i].y) maxy=pt[i].y;

if (minx>pt[i].x) minx=pt[i].x;

if (miny>pt[i].y) miny=pt[i].y;

}

pt[n+1]=pt[1];

pt[n+2]=pt[2];

pt[n+3]=pt[3];

pt[n+4]=pt[4];

**//求每条线段的转向**

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

{

cross = det(pt[i],pt[i+1], pt[i+1], pt[i+2]);

if (cross<0)

turn_right[i+1]=true;

else turn_right[i+1]=false;

}

**//两条边连续右转的为凸处,只有此时才可影响“核”肯恩存在的范围**

for (i=2; i<= n+1; i++)

if (turn_right[i] && turn_right[i+1])

{

if (pt[i].x==pt[i+1].x)

{

minn=pt[i].y;

maxn=pt[i+1].y;

Swap(minn, maxn);

if (minn>miny) miny=minn;

if (maxn<maxy) maxy=maxn;

}

else

{

minn=pt[i].x;

maxn=pt[i+1].x;

Swap(minn, maxn);

if (minn>minx) minx=minn;

if (maxn<maxx) maxx=maxn;

}

}

if (minx<=maxx && miny<=maxy)

printf("Floor #%d\nSurveillance is possible.\n\n", ++countn);

else printf("Floor #%d\nSurveillance is impossible.\n\n", ++countn);

}

return 0;

}

模拟退火

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
\#include <stdio.h>

\#include <stdlib.h>

\#include <math.h>

\#define Lim 0.999999

\#define EPS 1e-2

\#define PI acos(-1.0)

double Temp, maxx, minx, maxy, miny, lx, ly, dif;

int nt, ns, nc;

struct Target

{

double x, y;

}T[105];

struct Solution

{

double x, y;

double f;

}S[25], P, A;

double Dis(double x1, double y1, double x2, double y2)

{

return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));

}

void Seed(void)

{

int i, j;

for (i=0;i<ns;i++)

{

S[i].x=minx+((double)(rand()%1000+1)/1000.0)*lx;

S[i].y=miny+((double)(rand()%1000+1)/1000.0)*ly;

S[i].f=0.0;

for (j=0;j<nt;j++)

S[i].f=S[i].f+Dis(S[i].x,S[i].y, T[j].x, T[j].y);

}

}

void Trans(void)

{

int i, j, k;

double theta;

for (i=0;i<ns;i++)

{

P=S[i];

for (j=0;j<nc;j++)

{

theta=(((double)(rand()%1000+1))/1000.0)*2.0*PI;

A.x=P.x+Temp*cos(theta);

A.y=P.y+Temp*sin(theta);

if (A.x<minx||A.x>maxx||A.y<miny||A.y>maxy)

continue;

A.f=0.0;

for (k=0;k<nt;k++)

A.f=A.f+Dis(A.x,A.y,T[k].x,T[k].y);

dif=A.f-S[i].f;

if (dif<0.0)S[i]=A;

else

{

dif=exp(-dif/Temp);

if (dif>Lim) S[i]=A;

}

}

}

}

int main (void)

{

int i, k;

while (scanf("%d",&nt)==1&&nt)

{

maxx=maxy=0;

minx=miny=(1<<20);

for (i=0;i<nt;i++)

{

scanf("%lf %lf",&T[i].x,&T[i].y);

if (maxx<T[i].x)maxx=T[i].x;

if (minx>T[i].x)minx=T[i].x;

if (maxy<T[i].y)maxy=T[i].y;

if (miny>T[i].y)miny=T[i].y;

}

lx=maxx-minx;

ly=maxy-miny;

Temp=sqrt(lx*lx+ly*ly)/3.0;

ns=5, nc=10;

Seed();

while (Temp>EPS)

{

Trans();

Temp=Temp*0.40;

}

k=0;

for (i=1;i<ns;i++)

if (S[k].f>S[i].f)

k=i;

printf ("%.0lf\n", S[k].f);

}

return 0;

}

六边形坐标系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
**//第一种六边形坐标系**

\#include<stdio.h>

\#include<math.h>

\#include<string.h>

\#include<stdlib.h>

double Dis(double x1, double y1, double x2, double y2)

{

​ double dx=x1-x2;

​ double dy=y1-y2;

​ return sqrt(dx*dx+dy*dy);

}

void Get_KL(double L, double x, double y, int &k, int &l, double &cd)

{

​ k=floor((2.0*x)/(3.0*L));

​ l=floor((2.0*y)/(sqrt(3.0)*L));

​ double d1, d2, x1, y1, x2, y2;

​ if ((k+l)&1)

​ {

​ x1=k*L*1.5;

​ y1=(l+1.0)*L*sqrt(3.0)*0.5;

​ x2=(k+1.0)*L*1.5;

​ y2=l*L*sqrt(3.0)*0.5;

​ d1=Dis(x1,y1, x,y);

​ d2=Dis(x2,y2, x,y);

​ if (d1>d2)

​ {

​ k++;

​ cd=d2;

​ }

​ else

​ {

​ l++;

​ cd=d1;

​ }

​ }

​ else

​ {

​ x1=k*L*1.5;

​ y1=l*L*sqrt(3.0)*0.5;

​ x2=(k+1.0)*L*1.5;

​ y2=(l+1.0)*L*sqrt(3.0)*0.5;

​ d1=Dis(x1,y1, x,y);

​ d2=Dis(x2,y2, x,y);

​ if (d1>d2)

​ {

​ k++,l++;

​ cd=d2;

​ }

​ else cd=d1;

​ }

}

int My_Abs(int x)

{

​ if (x<0) return -x;

​ return x;

}

int main (void)

{

​ double L, x1, y1, x2, y2, ans, cd1, cd2;

​ int k1, l1, k2, l2;

​ while (scanf("%lf %lf %lf %lf %lf",&L,&x1,&y1,&x2,&y2)==5)

​ {

​ if (L==0.0&&x1==0.0&&y1==0.0&&x2==0.0&&y2==0.0) break;

​ Get_KL(L, x1, y1, k1, l1, cd1);

​ Get_KL(L, x2, y2, k2, l2, cd2);

​ if (k1==k2&&l1==l2) printf("%.3lf\n", Dis(x1,y1, x2,y2));

​ else

​ {

​ ans=cd1+cd2;

​ if (My_Abs(k1-k2) > My_Abs(l1-l2))

​ ans=ans+sqrt(3.0)*L*My_Abs(k1-k2);

​ else ans=ans+sqrt(3.0)*L*My_Abs(k1-k2)+sqrt(3.0)*L*(double)(My_Abs(l1-l2)-My_Abs(k1-k2))/2.0;

​ printf("%.3lf\n", ans);

​ }

​ }

​ return 0;

}



**//第二种六边形坐标系**

\#include <stdio.h>

\#include <string.h>

\#include <stdlib.h>

\#include <math.h>

struct A

{

​ int x, y, num;

}a[10001];

const int dec[6][2] = {{-1,1},{-1,0},{0,-1},{1,-1},{1,0},{0,1}};

bool adj(int x1, int y1, int x2, int y2)

{

​ if (x1 == x2 && abs(y1-y2) == 1) return true;

​ if (y1 == y2 && abs(x1-x2) == 1) return true;

​ if (x1 == x2 + 1 && y1 == y2 -1) return true;

​ if (x1 == x2 - 1 && y1 == y2 +1) return true;

​ return false;

}

bool flag[10001];

int main (void)

{

​ int i, j, k, x, u, v, cut, minn, cnt[6];

​ memset(cnt, 0, sizeof(cnt));

​ a[1].num = 1, cnt[1] = 1;

​ a[1].x = a[1].y = 0;

​ for (i = 2; i < 10001; i ++)

​ {

​ k = (int)((3.0+sqrt(12.0*i - 3.0))/6.0+0.0000001);

​ if (i == 3*(k-1)*(k-1)+3*(k-1)+1) k --;

​ j = i - (3*(k-1)*(k-1)+3*(k-1)+1);

​ **// 当前的六边形是第k层的第j个六边形**

​ if (j == 1) a[i].x = a[i-1].x, a[i].y = a[i-1].y + 1;

​ else

​ {

​ x = (j-1) / k;

​ a[i].x = a[i-1].x + dec[x][0], a[i].y = a[i-1].y + dec[x][1];

​ }

​ memset(flag, false, sizeof(flag));

​ x = 12*k-6, cut = 0;

​ for (u = i-1, v = 0; u>=1&&v<x; u --, v ++)

​ if (adj(a[u].x, a[u].y, a[i].x, a[i].y))

​ {

​ cut ++;

​ flag[a[u].num] = true;

​ if (cut == 3) break;

​ }

​ minn = 10001;

​ for (u = 1; u < 6; u ++)

​ if ((!flag[u])&&minn > cnt[u])

​ {

​ minn = cnt[u];

​ x = u;

​ }

​ a[i].num = x;

​ cnt[x] ++;

​ }

​ scanf ("%d", &x);

​ while (x --)

​ {

​ scanf ("%d", &i);

​ printf ("%d\n", a[i].num);

​ }

​ return 0;

}

用一个给定半径的圆覆盖最多的点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
**//同半径圆的圆弧表示**

\#include <stdio.h>

\#include <string.h>

\#include <stdlib.h>

\#include <math.h>

\#define PI acos(-1.0)

struct Point

{

double x, y;

}pt[2005];

double dis[2005][2005];

struct List

{

double a;

bool flag;

int id;

}list[8005];

int cnt;

double Dis(int i, int j)

{

double dx=pt[i].x-pt[j].x;

double dy=pt[i].y-pt[j].y;

return sqrt(dx*dx+dy*dy);

}

int Cmp(const void*p1, const void*p2)

{

struct List*a1=(struct List*)p1;

struct List*a2=(struct List*)p2;

if (a1->a<a2->a)return -1;

else if (a1->a==a2->a) return a1->id-a2->id;

else return 1;

}

int main (void)

{

int n, i, j, ans, num;

double r, theta, delta, a1, a2;

while (scanf("%d %lf",&n,&r)==2)

{

if (n==0&&r==0.0) break;

r=r+0.001;

r=r*2.0;

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

scanf("%lf %lf", &pt[i].x, &pt[i].y);

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

for (j=i+1;j<=n;j++)

{

dis[i][j]=Dis(i, j);

dis[j][i]=dis[i][j];

}

ans=0;

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

{

cnt=0;

for (j=1;j<=n;j++)

if ((j!=i)&&(dis[i][j]<=r))

{

theta=atan2(pt[j].y-pt[i].y, pt[j].x-pt[i].x);

if (theta<0.0) theta=theta+2.0*PI;

delta=acos(dis[i][j]/r);

a1=theta-delta;

a2=theta+delta;

list[++cnt].a=a1;

list[cnt].flag=true;

list[cnt].id=cnt;

list[++cnt].a=a2;

list[cnt].flag=false;

list[cnt].id=cnt;

}

qsort(list+1,cnt,sizeof(struct List),Cmp);

num=0;

for (j=1;j<=cnt;j++)

if (list[j].flag)

{

num++;

if (num>ans) ans=num;

}

else num--;

}

printf("It is possible to cover %d points.\n", ans+1);

}

return 0;

}

不等大的圆的圆弧表示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
intersection_circle_circle(circle[i].center, circle[i].r, circle[j].center, circle[j].r, p1, p2);

a1= atan2(p1.y-circle[j].center.y, p1.x-circle[j].center.x);

if (a1<0.0) a1=a1+2.0*PI;

a2= atan2(p2.y-circle[j].center.y, p2.x-circle[j].center.x);

if (a2<0.0) a2=a2+2.0*PI;



if (a1>a2)

{

tmp=a1;

a1=a2;

a2=tmp;

}

mid=(a1+a2)/2.0;

xtest = circle[j].center.x +circle[j].r*cos(mid);

ytest = circle[j].center.y +circle[j].r*sin(mid);



if (!point_in_circle(xtest, ytest, i))

{

circle[j].cnt++;

circle[j].line[circle[j].cnt].s=0;

circle[j].line[circle[j].cnt].t=a1;

circle[j].cnt++;

circle[j].line[circle[j].cnt].s=a2;

circle[j].line[circle[j].cnt].t=2.0*PI;

}

else

{

circle[j].cnt++;

circle[j].line[circle[j].cnt].s=a1;

circle[j].line[circle[j].cnt].t=a2;

}

矩形面积并

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
\#include<stdio.h>

\#include<string.h>

\#include<stdlib.h>

\#include<math.h>

struct Node

{

int l, r, cnt;

double cover;

}node[80005];

struct Point

{

double x;

double y1, y2;

int id_y1, id_y2, id_x;

bool flag;

}pt[20005];

double y[20005];

int total, cnty;

int cmp1(const void*p1, const void*p2)

{

double*a1=(double*)p1;

double*a2=(double*)p2;

if (*a1<*a2) return -1;

else if (*a1==*a2) return 0;

else return 1;

}

int cmp2(const void*p1, const void*p2)

{

struct Point*a1=(struct Point*)p1;

struct Point*a2=(struct Point*)p2;

if (a1->x<a2->x) return -1;

else if (a1->x==a2->x)

{

if (a1->id_x<a2->id_x) return -1;

else if (a1->id_x==a2->id_x) return 0;

else return 1;

}

else return 1;

}

int find(double target)

{

int head=1, tail=cnty, mid;

while (head<=tail)

{

mid=(head+tail)>>1;

if (y[mid]==target) return mid;

else if (y[mid]<target) head=mid+1;

else tail=mid-1;

}

return 0;

}

void Build(int l, int r, int s)

{

node[s].l=l;

node[s].r=r;

node[s].cnt=0;

node[s].cover=0.0;

if (l+1<r)

{

int mid=(l+r)>>1;

Build(l,mid,s<<1);

Build(mid,r,(s<<1)+1);

}

}

void Update(int s)

{

if (node[s].cnt>0)

node[s].cover=y[node[s].r]-y[node[s].l];

else if(node[s].l+1==node[s].r)

node[s].cover=0.0;

else node[s].cover=node[s<<1].cover+node[(s<<1)+1].cover;

}

void Insert(int l, int r, int s)

{

if (l<=node[s].l&&node[s].r<=r)

{

node[s].cnt++;

Update(s);

return;

}

if (node[s].l+1<node[s].r)

{

int mid=(node[s].l+node[s].r)>>1;

if (l<mid) Insert(l,r,s<<1);

if (r>mid) Insert(l,r,(s<<1)+1);

Update(s);

}

}

void Delete(int l, int r, int s)

{

if (l<=node[s].l&&node[s].r<=r)

{

if (node[s].cnt>0)

node[s].cnt--;

Update(s);

return;

}

if (node[s].l+1<node[s].r)

{

int mid=(node[s].l+node[s].r)>>1;

if (l<mid) Delete(l,r,s<<1);

if (r>mid) Delete(l,r,(s<<1)+1);

Update(s);

}

}

int main (void)

{

int n, i, j, countn=0;

double ans;

while (scanf("%d", &n)==1 && n)

{

cnty=total=0;

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

{

total++;

scanf("%lf %lf", &pt[total].x, &pt[total].y1);

pt[total].flag=true;

pt[total].id_x=total;

y[++cnty]=pt[total].y1;



total++;

scanf("%lf %lf", &pt[total].x, &pt[total].y2);

pt[total].flag=false;

pt[total].id_x=total;

y[++cnty]=pt[total].y2;



pt[total].y1=pt[total-1].y1;

pt[total-1].y2=pt[total].y2;

}

qsort(y+1, cnty, sizeof(double), cmp1);

j=cnty;

cnty=1;

for (i=2;i<=j;i++)

if (y[i]!=y[i-1])

y[++cnty]=y[i];



for (i=1;i<=total;i++)

{

pt[i].id_y1=find(pt[i].y1);

pt[i].id_y2=find(pt[i].y2);

}

qsort(pt+1, total, sizeof(struct Point), cmp2);



ans=0.0;

Build(1,cnty,1);

Insert(pt[1].id_y1, pt[1].id_y2, 1);

for (i=2;i<=total;i++)

{

ans=ans+(pt[i].x-pt[i-1].x)*node[1].cover;

if (pt[i].flag) Insert(pt[i].id_y1, pt[i].id_y2, 1);

else Delete(pt[i].id_y1, pt[i].id_y2, 1);

}

printf("%.0lf\n", ans+1e-10);

}

return 0;

}

矩形的周长并

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
\#include <stdio.h>

\#include <string.h>

\#include <stdlib.h>

struct Point

{

int x, y;

}plist[10001];

struct Line

{

int x, b, e, flag;

}llist[10001];

struct Item

{

int y, id, idx;

}ilist[10001];

struct Node

{

int l, r, c, m, line;

bool lf, rf;

}node[40005];

int ys[10001];

int cmp1(const void*p1, const void*p2)

{

struct Item *a1 = (struct Item*)p1;

struct Item *a2 = (struct Item*)p2;

return a1->y - a2->y;

}

int cmp2(const void*p1, const void*p2)

{

struct Item *a1 = (struct Item*)p1;

struct Item *a2 = (struct Item*)p2;

return a1->id - a2->id;

}

int cmp3(const void*p1, const void*p2)

{

struct Line *a1 = (struct Line*)p1;

struct Line *a2 = (struct Line*)p2;

return a1->x - a2->x;

}

void getm(int s)

{

if (node[s].c > 0)

{

node[s].m = ys[node[s].r-1] - ys[node[s].l-1];

node[s].line = 1;

node[s].rf = node[s].lf = true;

}

else if (node[s].r - node[s].l <= 1)

{

node[s].m = node[s].line = 0;

node[s].rf = node[s].lf = false;

}

else

{

node[s].m = node[s<<1].m + node[(s<<1)+1].m;

node[s].line = node[s<<1].line + node[(s<<1)+1].line;

if (node[s<<1].rf && node[(s<<1)+1].lf) node[s].line --;

node[s].lf = node[s<<1].lf;

node[s].rf = node[(s<<1)+1].rf;

}

}

void build(int l, int r, int s)

{

node[s].l = l;

node[s].r = r;

node[s].c = node[s].m = node[s].line;

if (node[s].r - node[s].l > 1)

{

int mid = (node[s].l + node[s].r)>>1;

build(l,mid,s<<1);

build(mid,r,(s<<1)+1);

}

}

void insert(int l, int r, int s)

{

if (l <= node[s].l && node[s].r <= r)

{

node[s].c ++;

getm(s);

}

if (node[s].r - node[s].l > 1)

{

int mid = (node[s].l + node[s].r)>>1;

if (l < mid) insert(l, r, s<<1);

if (mid < r) insert(l, r, (s<<1)+1);

getm(s);

}

}

void delet(int l, int r, int s)

{

if (l <= node[s].l && node[s].r <= r)

{

node[s].c --;

getm(s);

}

if (node[s].r - node[s].l > 1)

{

int mid = (node[s].l + node[s].r)>>1;

if (l < mid) delet(l, r, s<<1);

if (mid < r) delet(l, r, (s<<1)+1);

getm(s);

}

}

int main (void)

{

int n, i, j, l, r, x1, y1, x2, y2, tot, p, ans;

while (scanf ("%d", &n) == 1 && n)

{

for (i = 0; i < n; i ++)

{

scanf ("%d %d %d %d", &x1, &y1, &x2, &y2);

l = 2*i;

r = l + 1;



plist[l].x = x1;

plist[l].y = y1;

plist[r].x = x2;

plist[r].y = y2;



ilist[l].y = y1;

ilist[l].id = l;

ilist[r].y = y2;

ilist[r].id = r;

}

tot = 2*n;

qsort(ilist, tot, sizeof(struct Item), cmp1);

ys[0] = ilist[0].y;

ilist[0].idx = 0;

j = 0;

for (i = 1; i < tot; i ++)

{

if (ilist[i].y != ilist[i-1].y)

{

j ++;

ys[j] = ilist[i].y;

}

ilist[i].idx = j;

}

p = j + 1;

qsort(ilist, tot, sizeof(struct Item), cmp2);

for (i = 0; i < n; i ++)

{

l = 2*i;

r = l + 1;

llist[l].x = plist[l].x;

llist[l].b = ilist[l].idx;

llist[l].e = ilist[r].idx;

llist[l].flag = 1;



llist[r].x = plist[r].x;

llist[r].b = ilist[l].idx;

llist[r].e = ilist[r].idx;

llist[r].flag = 0;

}

qsort(llist, tot, sizeof(struct Line), cmp3);

build(1,p,1);

insert(llist[0].b+1, llist[0].e+1,1);

int now_m = node[1].m, now_line = node[1].line;

ans = now_m;

for (i = 1; i < tot; i ++)

{

if (llist[i].flag) insert(llist[i].b+1, llist[i].e+1, 1);

else delet(llist[i].b+1, llist[i].e+1, 1);

ans += (abs(node[1].m - now_m) + 2*(llist[i].x - llist[i-1].x)*now_line);

now_m = node[1].m;

now_line = node[1].line;

}

printf ("%d\n", ans);

}

return 0;

}

最近圆对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
\#include<iostream>

\#include<stdlib.h>

\#include<string.h>

\#include<set>

\#include <math.h>

using namespace std;

set <int>tree;

set <int>::iterator iter;

struct Point

{

double x;

int id, flag;

}p1[100001], p2[100001];

int tot1, tot2;

struct Q

{

double x,y, r;

}q[50001];

int cmp(const void*p1, const void*p2)

{

struct Point*a1=(struct Point*)p1;

struct Point*a2=(struct Point*)p2;

if (a1->x<a2->x) return -1;

else if (a1->x==a2->x) return a2->flag-a1->flag;

else return 1;

}

int cmp1(const void*p1, const void*p2)

{

struct Q*a1=(struct Q*)p1;

struct Q*a2=(struct Q*)p2;

if (a1->y<a2->y)return -1;

else if (a1->y==a2->y)return 0;

else return 1;

}

double dis(double x1, double y1, double x2, double y2)

{

return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));

}

bool judge(int i, int j, double d)

{

if (dis(q[i].x, q[i].y, q[j].x, q[j].y)<=q[i].r+q[j].r+2.0*d)

return true;

return false;

}

bool insert(int v,double d)

{

iter = tree.insert(v).first;

if (iter != tree.begin())

{

if (judge(v, *--iter,d))

{

return true;

}

++iter;

}

if (++iter != tree.end())

{

if (judge(v, *iter,d))

{

return true;

}

}

return false;

}

bool remove(int v,double d)

{

iter = tree.find(v);



if (iter != tree.begin() && iter != --tree.end())

{

int a = *--iter;

++iter;

int b = *++iter;

if (judge(a, b,d))

{

return true;

}

}

tree.erase(v);

return false;

}

bool check(double d)

{

int i=1, j=1;

while (i<=tot1&&j<=tot2)

{

if (p1[i].x-d<=p2[j].x+d)

{

if (insert(p1[i++].id, d))

return true;

}

else

{

if (remove(p2[j++].id, d))

return true;

}



}

while (i<=tot1)

{

if (insert(p1[i++].id, d))

return true;

}

while (j<=tot2)

{

if (remove(p2[j++].id, d))

return true;

}

return false;

}

int main (void)

{

int cases, n, i;

scanf("%d",&cases);

while (cases--)

{

scanf("%d",&n);

tot1=tot2=0;

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

scanf("%lf %lf %lf",&q[i].x,&q[i].y, &q[i].r);

qsort(q+1,n,sizeof(struct Q),cmp1);

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

{

tot1++;

p1[tot1].x=q[i].x-q[i].r;

p1[tot1].id=i;

p1[tot1].flag=1;



tot2++;

p2[tot2].x=q[i].x+q[i].r;

p2[tot2].id=i;

p2[tot2].flag=-1;

}

qsort(p1+1,tot1,sizeof(struct Point),cmp);

qsort(p2+1,tot2,sizeof(struct Point),cmp);



double head=0.0, tail=dis(q[1].x,q[1].y,q[2].x,q[2].y)+1.0, mid;

while (tail-head>1e-8)

{

tree.clear();

mid=(head+tail)/2.0;

if (check(mid))

{

tail=mid;

}

else head=mid;

}

printf ("%.6lf\n",2.0*head);

}

return 0;

}

求两个圆的面积交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
double area_of_overlap(point c1, double r1, point c2, double r2)

{

double a = distance(c1, c2), b = r1, c = r2;

double cta1 = acos((a * a + b * b - c * c) / 2 / (a * b)),

cta2 = acos((a * a + c * c - b * b) / 2 / (a * c));

double s1 = r1*r1*cta1 - r1*r1*sin(cta1)*(a * a + b * b - c * c) / 2 / (a * b);

double s2 = r2*r2*cta2 - r2*r2*sin(cta2)*(a * a + c * c - b * b) / 2 / (a * c);

return s1 + s2;

}

博弈论

Nim博弈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>  
#include <cstring>
#include <cstdio>
#define LL long long
#define mod 1000000007
#define sz 100005
using namespace std;
int sg[sz];
bool vis[sz];
int main()
{
//´ò±í³ÌÐò
/*int tmp;
sg[0]=0;
for(int i=1;i<=50;i++)
{
memset(vis,0,sizeof(vis));
for(int j=0;j<i;j++)
vis[sg[j]]=1;
for(int k=1;k<i;k++)
{
for(int m=1;m<i;m++)
{
int u=i-k-m;
if(u>0)
{
tmp=sg[k]^sg[m]^sg[u];
vis[tmp]=1;
}
else
break;
}
}
for(int x=0;;x++)
if(!vis[x])
{
sg[i]=x;
printf("sg[%d]: %d\n",i,x);
break;
}
}*/
int t,n,tmp,s;
scanf("%d",&t);
while(t--)
{
s=0;
scanf("%d",&n);
while(n--)
{
scanf("%d",&tmp);
if(tmp%8==7)
s^=(tmp+1);
else if(tmp%8==0)
s^=(tmp-1);
else
s^=tmp;
}
if(s)
printf("First player wins.\n");
else
printf("Second player wins.\n");
}
return 0;
}

威佐夫博弈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;

int wzf(int a,int b){
if(a<b){
a^=b;
b^=a;
a^=b;
}
int k=a-b;
a=(int)(k*(1+sqrt(5))/2.0);
if(a==b)
return 1;
else
return 0;
}

int main(){
for(int i=1;i<100;i++)
for(int j=1;j<100;j++)
if(wzf(i,j)) printf("(%d,%d) %d\n",i,j,i-j);
}

其他

整数划分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<iostream>

using namespace std;

int d[1000][10], n, k;

int main()

{

cin >> n >> k;

d[0][0] = 1;

for (int i = 1; i <= n; i++)
d[i][1] = 1;

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

for (int j = 1; j <= k; j++)

if (i >= j)

d[i][j] = d[i - j][j] + d[i - 1][j - 1];

cout << d[n][k]<<endl;

return 0;

}

区间K大数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
#include <iostream>
#include <cstring>
#include <cstdio>
#define MAXN 10010
#define MAXE 100010
using namespace std;
int head[MAXN],tot1,tot2;
struct Edge
{
int u,v,next;
} e1[MAXE],e2[MAXN];
void addEdge(int u,int v,Edge* edge,int& tol)
{
edge[tol].u=u;
edge[tol].v=v;
edge[tol].next=head[u];
head[u]=tol++;
}
int n,m;
int low[MAXN],dfn[MAXN],stack[MAXN],belong[MAXN],num[MAXN];
bool instack[MAXN];
int scc,top,INDEX;
void Tarjan(int u)
{
int v;
low[u]=dfn[u]=++INDEX;
stack[top++]=u;
instack[u]=true;
for(int i=head[u]; i!=-1; i=e1[i].next)
{
v=e1[i].v;
if(!dfn[v])
{
Tarjan(v);
if(low[u]>low[v])
low[u]=low[v];
}
else if(instack[v]&&low[u]>dfn[v])
low[u]=dfn[v];
}
if(low[u]==dfn[u])
{
++scc;
do
{
v=stack[--top];
instack[v]=false;
belong[v]=scc;
num[scc]++;
}
while(u!=v);
}
}
int inde[MAXN],outde[MAXN];
void solve()
{
memset(dfn,0,sizeof(dfn));
memset(instack,false,sizeof(instack));
memset(num,0,sizeof(num));
scc=top=INDEX=0;
for(int i=1; i<=n; ++i)
if(!dfn[i])
Tarjan(i);
tot2=0;
memset(head,-1,sizeof(head));
memset(inde,0,sizeof(inde));
memset(outde,0,sizeof(outde));
int u,v;
for(int i=0; i<m; ++i)
{
u=belong[e1[i].u];
v=belong[e1[i].v];
if(u!=v)
{
addEdge(u,v,e2,tot2);
inde[v]++;
outde[u]++;
}
}
int a=0,b=0;
for(int i=1; i<=scc; ++i)
{
if(!inde[i])
a++;
if(!outde[i])
b++;
}
if(scc==1)
printf("0\n");
else
printf("%d\n",max(a,b));
}
int main()
{
int zushu;
scanf("%d",&zushu);
while(zushu--)
{
scanf("%d%d",&n,&m);
tot1=0;
memset(head,-1,sizeof(head));
int u,v;
for(int i=0; i<m; ++i)
{
scanf("%d%d",&u,&v);
addEdge(u,v,e1,tot1);
}
solve();
}
return 0;
}
22. 22. 22. 22. 区间 KKKK 大数
//POJ 2104
#include <cstdio>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
const int NMAX = 100000;
const int LOGNMAX = 17 +1;
int sortseq[LOGNMAX][NMAX];
int num[NMAX];
struct node
{
int l,r,d;
node * pl,* pr;
} mem[(NMAX<<1)+100];
int mempos,n,m;
node * root;
node * make_tree(int l,int r,int d)
{
node * rt = mem+(mempos ++);
rt->l = l;
rt->r = r;
rt->d = d;
if (l == r)
{
sortseq[d][l] = num[l];
return rt;
}
int mid = (l+r) >> 1;
rt->pl = make_tree(l,mid,d+1);
rt->pr = make_tree(mid+1,r,d+1);
int i=l,j=mid+1,k=l;
while (i<=mid && j<=r)
{
if (sortseq[d+1][i] < sortseq[d+1][j])
sortseq[d][k++] =
sortseq[d+1][i++];
else
sortseq[d][k++] = sortseq[d+1][j++];
}
while (i<=mid)
sortseq[d][k++] = sortseq[d+1][i++];
while (j<=r)
sortseq[d][k++] = sortseq[d+1][j++];
return rt;
}
int s,t,rank;
int query(node * rt,int val)
{
int i,mid,ret;
if (s <= rt->l && rt->r <= t)
{
if (val <= sortseq[rt->d][rt->l])
return 0;
else if (sortseq[rt->d][rt->r] < val)
return rt->r - rt->l +1;
else if (sortseq[rt->d][rt->r] == val)
return rt->r - rt->l;
int l = rt->l, r = rt->r, mid;
while (l <= r)
{
mid = (l+r) >> 1;
if (val <= sortseq[rt->d][mid])
r = mid-1;
else
l = mid+1;
}
return l - rt->l;
}
else
{
ret = 0;
mid = (rt->l+rt->r) >> 1;
if (s <= mid)
ret += query(rt->pl,val);
if (mid+1 <= t)
ret += query(rt->pr,val);
return ret;
}
}
// 二分查找时遇到相同值的处理非常重要
int main()
{
int i,j,l,r;
scanf("%d %d",&n,&m);
for (i=0; i<n; i++)
scanf("%d",num+i);
mempos = 0;
root = make_tree(0,n-1,0);
while (m --)
{
s = get_val()-1;
t = get_val()-1;
rank = get_val()-1;
l = 0, r = n-1;
while (l <= r)
{
int mid = (l+r) >> 1;
// 二分查找sortseq[0][mid]在区间[s,t]中的排名
int pos = query(root,sortseq[0][mid]);
if (rank < pos)
r = mid-1;
else
l = mid+1;
}
printf("%d\n",sortseq[0][r]);
}
}

离散化

1
2
3
4
5
6
7
8
int getid(int x){
return lower_bound(v.begin(),v.end(),x) - v.begin() + 1;
}
for(int i = 1;i<=n;++i){
scanf("%d",&a[i]);
v.push_back(a[i]);
}
sort(v.begin(),v.end()), v.erase(unique(v.begin(),v.end()),v.end());

位运算

统计1的个数

1
2
3
4
5
6
7
8
int NumberOfOne(int n) {
int count = 0;
while(n) {
n &= (n-1);
count++;
}
return count;
}

strtok 和 sscanf 结合输入

空格作为分隔输入,读取一行的整数:

1
2
3
4
5
6
7
8
gets(buf);
int v;
char *p = strtok(buf," ");
while(p)
{
sscanf(p,"%d",&v);
p = strtok(NULL," ");
}

输入输出挂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//适用于正负整数
template <class T>inline bool scan_d(T &ret)
{
char c;
int sgn;
if(c=getchar(),c==EOF)
return 0; //EOF
while(c!='−'&&(c<'0'||c>'9'))
c=getchar();
sgn=(c=='−')?−1:1;
ret=(c=='−')?0:(c−'0');
while(c=getchar(),c>='0'&&c<='9')
ret=ret*10+(c−'0');
ret*=sgn;
return 1;
}
inline void out(int x)
{
if(x>9)
out(x/10);
putchar(x%10+'0')
}

文章结束了,但我们的故事还在继续
坚持原创技术分享,您的支持将鼓励我继续创作!