hdu2389Rain on your Parade
//做啦好久老是WA,不知到为什么,刚刚开始吧他们都设成是双浮点型,老是过不了;改成整形就过啦;
//后来又是超时,吧cin改成scanf();果断过!!!!!
#include<stdio.h>
#include<queue>
#include<iostream>
#include<string.h>
#include<math.h>
using namespace std;
#define eps 1e-6
const int MAXN=3005;
const int INF=1<<28;
int g[MAXN][MAXN],Mx[MAXN],My[MAXN],Nx,Ny;int dx[MAXN],dy[MAXN],dis;
bool vst[MAXN];
struct Node1{
int x,y,s;
}guests[MAXN];
struct Node2{
int x,y;
}um[MAXN];
double distance(Node1 a,Node2 b){
double x=a.x-b.x;
double y=a.y-b.y;
return sqrt(x*x+y*y);
}
bool searchP(void){
queue<int> Q;
dis = INF;
memset(dx, -1, sizeof(dx));
memset(dy, -1, sizeof(dy));
for (int i = 0; i < Nx; i++)
if (Mx[i] == -1){
Q.push(i); dx[i] = 0;
}
while (!Q.empty()) {
int u = Q.front(); Q.pop();
if (dx[u] > dis) break;
for (int v = 0; v < Ny; v++)
if (g[u][v] && dy[v] == -1) {
dy[v] = dx[u]+1;
if (My[v] == -1) dis = dy[v];
else{
dx[My[v]] = dy[v]+1;
Q.push(My[v]);
}
}
}
return dis != INF;
}
bool DFS(int u){
for (int v = 0; v < Ny; v++)
if (!vst[v] && g[u][v] && dy[v] == dx[u]+1) {
vst[v] = 1;
if (My[v] != -1 && dy[v] == dis) continue;
if (My[v] == -1 || DFS(My[v])) {
My[v] = u; Mx[u] = v;
return 1;
}
}
return 0;
}
int MaxMatch(void){
int res = 0;
memset(Mx, -1, sizeof(Mx));
memset(My, -1, sizeof(My));
while (searchP()) {
memset(vst, 0, sizeof(vst));
for (int i = 0; i < Nx; i++)
if (Mx[i] == -1 && DFS(i)) res++;
}
return res;
}
int main(){
//freopen("test.in","r",stdin);
//freopen("test.out","w",stdout);
int n,m,t,i,j;
int T,iCase=0;
scanf("%d",&T);
while(T--)
{
iCase++;
scanf("%d",&t);
scanf("%d",&m);
for(i=0;i<m;i++)
scanf("%d%d%d",&guests[i].x,&guests[i].y,&guests[i].s);
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d%d",&um[i].x,&um[i].y);
Nx=m;Ny=n;
memset(g,0,sizeof(g));
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
if(distance(guests[i],um[j])/guests[i].s-t<eps)
{
g[i][j]=1;
}
}
}
printf("Scenario #%d:\n%d\n\n",iCase,MaxMatch());
}
return 0;
}
二分图匹配匈牙利算法(邻接表矩阵实现
#include <iostream>
#include <cstdio>
using namespace std;
int const MAXN = 250;
int graph[MAXN][MAXN], cnt[MAXN];
//邻接表矩阵,点度
bool ck[MAXN];//记录是否被访问
int match[MAXN];//匹配数组,记录右端到左端的匹配
int V, E;//点数、边数
bool search(int G[][MAXN], int k)
{//找增广边
}
int hungary(int G[][MAXN], int left)
{//传入矩阵和左端点数,传出匹配的对数
}
Hopcroft-Carp的算法
/********************************************** 二分图匹配(Hopcroft-Carp的算法)。 初始化:g[][]邻接矩阵 调用:res=MaxMatch(); Nx,Ny要初始化!!! 时间复杂大为 O(V^0.5 E) 适用于数据较大的二分匹配 ***********************************************/ const int MAXN=3001; const int INF=1<<28; int g[MAXN][MAXN],Mx[MAXN],My[MAXN],Nx,Ny; int dx[MAXN],dy[MAXN],dis; bool vst[MAXN]; bool searchP() { queue<int>Q; dis=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=0;i<Nx;i++) if(Mx[i]==-1) { Q.push(i); dx[i]=0; } while(!Q.empty()) { int u=Q.front(); Q.pop(); if(dx[u]>dis) break; for(int v=0;v<Ny;v++) if(g[u][v]&&dy[v]==-1) { dy[v]=dx[u]+1; if(My[v]==-1) dis=dy[v]; else { dx[My[v]]=dy[v]+1; Q.push(My[v]); } } } return dis!=INF; } bool DFS(int u) { for(int v=0;v<Ny;v++) if(!vst[v]&&g[u][v]&&dy[v]==dx[u]+1) { vst[v]=1; if(My[v]!=-1&&dy[v]==dis) continue; if(My[v]==-1||DFS(My[v])) { My[v]=u; Mx[u]=v; return 1; } } return 0; } int MaxMatch() { int res=0; memset(Mx,-1,sizeof(Mx)); memset(My,-1,sizeof(My)); while(searchP()) { memset(vst,0,sizeof(vst)); for(int i=0;i<Nx;i++) if(Mx[i]==-1&&DFS(i)) res++; } return res; }
KMP
字符串匹配算法:KMP学习心得

这周的数据结构课讲的是串,本以为老师会讲解KMP算法的,谁知到他直接略过了...没办法只能自己研究,这一琢磨就是3天,期间我都有点怀疑自己的智商...不过还好昨天半夜终于想明白了个中缘由,总结一些我认为有助于理解的关键点好了...
书上有的东西我就不说了,那些东西网上一搜一大片,我主要说一下我理解的由前缀函数生成的next数组的含义,先贴出求next数组的方法。
当一个字符串以0为起始下标时,next[i]可以描述为"不为自身的最大首尾重复子串长度"。
也就是说,从模式串T[0...i-1]的第一个字符开始截取一段长度为m(m < i-1)子串,再截取模式串T[0...i-1]的最后m个字符作为子串,如果这两个子串相等,则该串就是一个首尾重复子串。我们的目的就是要找出这个最大的m值。
例如:
若 i = 4 ,则 i - 1 = 3 , m = next[4] = 2
从T[0...3]截取长度为2的子串,为"ab"
从T[0..3]截取最后2个字符,为"ab"
此时2个子串相等,则说明 next[4] = 2 成立,也可证明 m = 2 为最大的m值。
本来一开始我是没有加"不为自身"这个限制条件的,可是后来我发现一种情况:
若 i = 4 ,则 i - 1 = 3 , m = next[4] = 3
从T[0...3]截取长度为3的子串,为"aaa"
从T[0..3]截取最后3个字符,为"aaa"
此时2个子串相等,则说明 next[4] = 3 成立。
但是我发现如果next[4] = 4:
从T[0...3]截取长度为4的子串,为"aaaa"
从T[0..3]截取最后4个字符,为"aaaa"
此时2个子串也是相等的,那么是不是说明 next[4] 应该等于4呢?
仔细观察后发现,如果 next[4] = 4 ,那么T[0...3]的前4个字符和后4个字符是重合的,并且重复子串和T[0...3]也是相等的。看过教材后发现教材中给出的前缀函数定义有一句为:next[j] = max{k | 0 < k < j 且 'p[0]...p[k-1]' = 'p[j-k+1]...p[j-1]'},应该不包含子串为本身的情况...
这样再做PKU 2406 和 PKU 1961 的时候就很简单了,用 length - next[length] 求出"不为自身的最大首尾重复子串长度",此时需要多求一位next[length]值(而next[length]刚好反映了lenght之前不为。。的长度),若最大重复子串的长度是length的非1整数倍,则证明字符串具有周期重复性质。
PKU 2752 是求 前缀 == 后缀的长度,也就是首尾重复子串长度,利用next数组记录的"不为自身的最大首尾重复子串长度"可以马上得到结果。
#include<iostream>
using namespace std;
int a[1000010],b[10010],next[10010];
int lena,lenb;
void inset()
{
int i;
scanf("%d%d",&lena,&lenb);
for(i=0;i<lena;i++)
scanf("%d",&a[i]);
for(i=0;i<lenb;i++)
scanf("%d",&b[i]);
}
void Gurm()
{
int j=0,k=-1;
next[0]=-1;
while(j<lenb)
{
if(k==-1 || b[j]==b[k])
{
++j;
++k;
next[j]=k;
}
else
{
k=next[k];
}
}
}
int kmp()
{
int i=0,j=0;
Gurm();
while(i<lena && j<lenb)
{
if(j==-1 || a[i]==b[j] )
{
i++;
j++;
}
else
{
j=next[j];
}
}
if(j<lenb) return -1;
else return i-j+1;
}
int main()
{
//freopen("D:\\in.txt","r",stdin);
int R;scanf("%d",&R);
while(R--)
{
inset();
printf("%d\n",kmp());
}
return 0;
}
KMP:next[]的应用。
* 一般next[i]与优化next[i]的区别:
*如果模式串p下标为i的字符(字符第一个的下标为0)的前k个字符与开头前k个字符相等(0=<k<i 注意这里没有等于i)
* 对于一般的next[i],不管p[i]是否等于p[k+1],next[i]都是等于k;
* 对于优化后的next[i],如果p[i]不等于p[k+1],则next[i]=k,反之,next[i]=0.
* 这题的next[]是从0求到n,有n+1个值,因此对于next[i]=k的意义(0除外)就为:字符串下标为i的前k-1个字符与字符串头k个字符相等(上面提到的next[i]是与前k个字符与头k个字符相等next[i]才等于k)。
* 对于长度为i个字符串,i-next[i](满足i % (i-next[i])==0)代表的意义就是 长度为i的字符串 的 最小循环子串的长度
* 因此 字符串中存在周期的子串的最大循环次数=i/ (i-next[i]);
*
Hopcroft_Karp算法
在匈牙利算法中,我们每次寻找一条增广路来增加匹配集合M.可以证明,每次找增广路的复杂度是O(E),一共需要增广O(V)次,因此总时间复杂度为O(VE).为了降低时间复杂度,在Hopcroft Karp算法中,我们在增加匹配集合M时,每次寻找多条增广路.可以证明,这样迭代次数最多为2*V^0.5,所以,时间复杂度就降到了O(V^0.5*E).
001 |
#include <iostream> |
002 |
#include <cstdio> |
003 |
#include <cstring> |
004 |
#include <algorithm> |
005 |
#include <vector> |
006 |
#include <cmath> |
007 |
#include <iterator> |
008 |
using namespace std; |
009 |
|
010 |
struct NodeGuest |
011 |
{ |
012 |
double x, y, speed; |
013 |
}ng[3010]; |
014 |
|
015 |
struct NodeNmbre |
016 |
{ |
017 |
double x, y; |
018 |
}nn[3010]; |
019 |
|
020 |
|
021 |
int T, cntGuest, cntUmbre, match; |
022 |
int disx[3010], disy[3010], matx[3010], maty[3010], que[3010]; |
023 |
double t; |
024 |
vector< int > mp[3010]; |
025 |
|
026 |
|
027 |
|
028 |
double getTime( int a, int b) |
029 |
{ |
030 |
double dis = sqrt ( (ng[a].x - nn[b].x) * (ng[a].x - nn[b].x) + (ng[a].y - nn[b].y) * (ng[a].y - nn[b].y)); |
031 |
return dis/ng[a].speed; |
032 |
} |
033 |
|
034 |
|
035 |
bool bfs() |
036 |
{ |
037 |
int i, j, fore = 0, rear = 0; |
038 |
bool flag = false ; |
039 |
vector< int >::iterator ite; |
040 |
for (i=0; i<cntGuest; ++i){ //找出中还没有匹配的点 |
041 |
if (matx[i] == -1) que[rear++] = i; |
042 |
disx[i] = 0; |
043 |
} |
044 |
for (i=0; i<cntUmbre; ++i) disy[i] = 0; |
045 |
while (fore<rear){ //从这些没有匹配的点里,找路径 |
046 |
int x = que[fore++]; |
047 |
for (ite=mp[x].begin(); ite!=mp[x].end(); ++ite){ |
048 |
if (disy[*ite] == 0){ |
049 |
disy[*ite] = disx[x] + 1; |
050 |
if (maty[*ite] == -1) flag = true ; //找到一条路径,则返回值是正的 |
051 |
else { //找不到路径,则把前向点如队列 |
052 |
disx[maty[*ite]] = disy[*ite] + 1; |
053 |
que[rear++] = maty[*ite]; |
054 |
} |
055 |
} |
056 |
} |
057 |
} |
058 |
return flag; |
059 |
} |
060 |
|
061 |
|
062 |
|
063 |
bool dfs( int x) |
064 |
{ |
065 |
vector< int >::iterator ite; |
066 |
for (ite=mp[x].begin(); ite!=mp[x].end(); ++ite){ |
067 |
if (disy[*ite] == disx[x] + 1){ |
068 |
disy[*ite] = 0; |
069 |
if (maty[*ite] == -1 || dfs(maty[*ite])){ |
070 |
matx[x] = *ite; |
071 |
maty[*ite] = x; |
072 |
return 1; |
073 |
} |
074 |
} |
075 |
} |
076 |
return false ; |
077 |
} |
078 |
|
079 |
|
080 |
|
081 |
int Hopcroft_Karp() |
082 |
{ |
083 |
int i; |
084 |
match = 0; |
085 |
memset (matx, -1, sizeof (matx)); |
086 |
memset (maty, -1, sizeof (maty)); |
087 |
while (bfs()){ |
088 |
for (i=0; i<cntGuest; ++i){ |
089 |
if (matx[i] == -1 && dfs(i)) ++match; |
090 |
} |
091 |
} |
092 |
return match; |
093 |
} |
094 |
|
095 |
|
096 |
int main() |
097 |
{ |
098 |
// freopen("c:/aaa.txt", "r", stdin); |
099 |
int ca = 1; |
100 |
scanf ( "%d" , &T); |
101 |
while (T--){ |
102 |
scanf ( "%lf %d" , &t, &cntGuest); |
103 |
int i, j; |
104 |
for (i=0; i<cntGuest; ++i) scanf ( "%lf %lf %lf" , &ng[i].x, &ng[i].y, &ng[i].speed); |
105 |
scanf ( "%d" , &cntUmbre); |
106 |
for (i=0; i<cntUmbre; ++i) scanf ( "%lf %lf" , &nn[i].x, &nn[i].y); |
107 |
for (i=0; i<cntGuest; ++i) mp[i].clear(); |
108 |
for (i=0; i<cntGuest; ++i){ |
109 |
for (j=0; j<cntUmbre; ++j){ |
110 |
double tt = getTime(i, j); |
111 |
if (tt <= t) mp[i].push_back(j); |
112 |
} |
113 |
} |
114 |
|
115 |
printf ( "Scenario #%d:\n%d\n\n" , ca++, Hopcroft_Karp()); |
116 |
} |
117 |
return 0; |
118 |
} |
匈牙利算法___最大匹配
#include<stdio.h> #include<string.h> bool g[201][201]; int n,m,ans; bool b[201]; int link[201]; bool init() { int _x,_y; memset(g,0,sizeof(g)); memset(link,0,sizeof(link)); ans=0; if(scanf("%d%d",&n,&m)==EOF)return false; for(int i=1;i<=n;i++) { scanf("%d",&_x); for(int j=0;j<_x;j++) { scanf("%d",&_y); g[ i ][_y]=true; } } return true; } bool find(int a) { for(int i=1;i<=m;i++) { if(g[a][ i ]==1&&!b[ i ]) { b[ i ]=true; if(link[ i ]==0||find(link[ i ])) { link[ i ]=a; return true; } } } return false; } int main() { while(init()) { for(int i=1;i<=n;i++) { memset(b,0,sizeof(b)); if(find(i))ans++; } printf("%d\n",ans); } }
每次增广时间为O(E),最多进行O(V)次迭代,时间复杂度为O(VE).