摘要: 判断点q是否在多边形内的一种方法,过q作水平射线L, 如果L与多边形P的边界不相交,则q在P的外部。否则, L和P的边界相交,具体地说,交点个数为奇(偶)数时,点q在P的内(外)部。(参考 计算几何P19 )
/**//*判断点q是否在多边形内的一种方法,过q作水平射线L,如果L与多边形P的边界不相交,则q在P的外部。否则,L和P的边界相交,具体地说,...
阅读全文
posted @
2011-02-06 22:55 小阮 阅读(379) |
评论 (0) |
编辑 收藏
凸包入门题目, 我用的是O(nlgn)的graham算法, 该算法的原理可以参照算法导论相关章节

/**//*
ID: lorelei3
TASK: fc
LANG: C++
*/

#include <iostream>
#include <fstream>
#include <iomanip>
#include <cmath>

using namespace std;

const int STACKSIZE = 1000;
const int MAXN = 10001;
const int INF = 0x7FFFFFFF;


struct Point
{
double x,y;
};

ifstream fin("fc.in");
ofstream fout("fc.out");

Point p0, points[MAXN];


double cross(Point &p1s, Point &p1e, Point &p2s, Point &p2e)
{
double x1 = p1e.x - p1s.x;
double y1 = p1e.y - p1s.y;

double x2 = p2e.x - p2s.x;
double y2 = p2e.y - p2s.y;

return x1*y2-x2*y1;
}


double dis(Point &p1, Point &p2)
{
return sqrt((p2.y-p1.y)*(p2.y-p1.y)+(p2.x-p1.x)*(p2.x-p1.x));
}


int cmp(const void *A, const void *B)
{
Point *p1 = (Point*)A;
Point *p2 = (Point*)B;

double res = cross(p0, *p1, p0, *p2);
if(res>0)
return -1;
else if(res==0 && dis(p0,*p1) > dis(p0, *p2))
return -1;
else
return 1;
}

int n;

void input()
{
int loc=0;
double minx = INF, miny = INF;
fin>>n;

for(int i=0; i<n; ++i)
{
fin>>points[i].x >>points[i].y;

if(points[i].y < miny)
{
miny = points[i].y;
minx = points[i].x;
p0 = points[i];
loc = i;

}else if(points[i].y == miny)
{

if(points[i].x < minx)
{
miny = points[i].y;
minx = points[i].x;
p0 = points[i];
loc = i;
}
}
}
points[loc] = points[--n];

qsort(points, n, sizeof(Point), cmp);
}

Point stack[STACKSIZE];
int top;

void graham()
{

stack[++top] = p0;
stack[++top] = points[0];
stack[++top] = points[1];


for(int i=2; i<n; ++i)
{
while(cross(stack[top], points[i], stack[top], stack[top-1])<0 )
top--;
stack[++top] = points[i];
}
}

double ans=0;

void output()
{
int tmp = top;

while(tmp!=1)
{
ans += dis(stack[tmp], stack[tmp-1]);
tmp--;
}

ans += dis(p0, stack[top]);
fout.setf(ios::fixed);
fout.precision(2);
fout<<ans<<endl;

}


int main()
{

input();

graham();

output();

return 0;
}


posted @
2011-02-05 22:16 小阮 阅读(198) |
评论 (0) |
编辑 收藏
摘要: 根据题意,每个矩形总能找到他的四个角的坐标,先找出各个矩形,再遍历每个矩形的四条边,例如:若在遍历矩形A的四条边时候,遇到B。则图中存在边A->B如此建立边的关系之后即刻拓扑排序。最后对结果进行排序。PS:结果数量比较大。
/**//*ID: lorelei3TASK: frameupLANG: C++*/#include <fstream&g...
阅读全文
posted @
2011-02-04 16:48 小阮 阅读(368) |
评论 (0) |
编辑 收藏
根据最大流最小割定理,最大流的值flow就等于最小割的流量。
求最小割的边集:枚举每条边,该边的值为t, 从图中去掉这条边,然后求最大流maxt。
如果 maxt + t = flow 则这条边属于最小割的边集,flow -= t 。继续枚举。
另外,为了构造解,我记录了输入的顺序并对边的大小和答案进行了排序。 我看到有些牛人的题解不需要排序,学习中。

/**//*
ID: lorelei3
TASK: milk6
LANG: C++
*/

#include <fstream>
#include <queue>
#include <algorithm>
#include <memory.h>

using namespace std;

const int MAXM = 1005;
const int MAXN = 33;
const int INF = 0x7FFFFFFF;

ifstream fin("milk6.in");
ofstream fout("milk6.out");


struct Edge
{
int index, s, t;
long cost ;


bool operator < ( const Edge &e)const
{
return (cost>e.cost) || (cost==e.cost && index<e.index );
}
};

int n,m;
int cnt;
Edge edges[MAXM];

long c[MAXN][MAXN];
long tmp[MAXN][MAXN];



void input()
{
fin>>n>>m;

for(int i=1; i<=m; ++i)
{
edges[i].index=i;
fin>>edges[i].s>>edges[i].t>>edges[i].cost;
c[edges[i].s][edges[i].t] += edges[i].cost;
}
memcpy(tmp, c, sizeof( long)*MAXN*MAXN);
}

long pre[MAXN], delta[MAXN];


bool bfs(int s, int t)
{

queue<int> Q;

memset(pre, 0, sizeof(pre));
memset(delta, 0, sizeof(delta));

delta[s]=INF;
Q.push(s);

while(!Q.empty())
{
int cur = Q.front();
Q.pop();

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

if(delta[i]==0 && c[cur][i]>0 )
{
delta[i] = delta[cur]<c[cur][i] ? delta[cur] : c[cur][i];
pre[i] = cur;
Q.push(i);
}
}
}
if(delta[t]==0)
return false;

return true;
}


long edmonds_karp(int s, int t)
{
long ans=0;

while(bfs(s,t))
{

for(int i=t; i!=s; i=pre[i])
{
c[pre[i]][i] -= delta[t];
c[i][pre[i]] += delta[t];
}
ans += delta[t];
}
return ans;
}

int tot;
int ans[MAXM];
long maxflow, flow;


void solve()
{

sort(edges+1, edges+m+1);

flow = edmonds_karp(1, n);
maxflow = flow;


for(int i=1; i<=m; ++i)
{
long t = edges[i].cost;
memcpy(c, tmp, sizeof( long)*MAXN*MAXN);

c[edges[i].s][edges[i].t] -= edges[i].cost;

long maxt = edmonds_karp(1, n);


if(maxt+t == flow)
{
ans[tot++] = edges[i].index;
flow -= edges[i].cost;
tmp[edges[i].s][edges[i].t] -= edges[i].cost;
}
}
}


void output()
{
fout<<maxflow<<" "<<tot<<endl;

sort(ans, ans+tot);
for(int i=0; i<tot; ++i)
fout<<ans[i]<<endl;

}


int main()
{

input();

solve();

output();

return 0;
}


posted @
2011-02-02 13:57 小阮 阅读(850) |
评论 (0) |
编辑 收藏
一开始想到暴搜,但是状态太多,肯定TLE。
了USACO上给出构造法求解:
3
3 5 6 4 2 1 3 5 7 6 4 2 3 5 4
2 1 -2 -2 -1 2 2 2 -1 -2 -2 1 2 -1
4
4 6 7 5 3 2 4 6 8 9 7 5 3 1 2 4 6 8 7 5 3 4 6 5
2 1 -2 -2 -1 2 2 2 1 -2 -2 -2 -2 1 2 2 2 -1 -2 -2 1 2 -1
5
5 7 8 6 4 3 5 7 9 10 8 6 4 2 1 3 5 7 9 11 10 8 6 4 2 3 5 7 9 8 6 4 5 7 6
2 1 -2 -2 -1 2 2 2 1 -2 -2 -2 -2 -1 2 2 2 2 2 -1 -2 -2 -2 -2 1 2 2 2 -1 -2 -2 1 2 -1
6
6 8 9 7 5 4 6 8 10 11 9 7 5 3 2 4 6 8 10 12 13 11 9 7 5 3 1 2 4 6 8 10 12 11 9 7 5 3 4 6 8 10 9 7 5 6 8 7
2 1 -2 -2 -1 2 2 2 1 -2 -2 -2 -2 -1 2 2 2 2 2 1 -2 -2 -2 -2 -2 -2 1 2 2 2 2 2 -1 -2 -2 -2 -2 1 2 2 2 -1 -2 -2 1 2 -1
规律很明显。

/**//*
ID: lorelei3
TASK: shuttle
LANG: C++
*/

#include <fstream>

using namespace std;

const int MAX = 500;

int n;
int two=2, one=1;
int a[MAX];

bool flag = true;


int main()
{

ifstream fin("shuttle.in");
ofstream fout("shuttle.out");

fin>>n;

int loc=0, k=1;

while(k!=0)
{


if(k==n)
{
flag=false;
one = -one;
}
int t=k;

while(t!=0)
{
a[loc++] = two;
t--;
}
a[loc++]=one;

two = -two;
one = -one;

if(k<n && flag)
k++;
else
k--;
}

int res=n;
fout<<n<<" ";


for(int i=0, cnt=2; i<loc-1; ++i,++cnt)
{

if(cnt==20)
{
fout<<(res+=a[i])<<endl;
cnt=0;
}
else
fout<<(res+=a[i])<<" ";
}
res+=a[loc-1];
fout<<res<<endl;

return 0;
}
posted @
2011-01-30 22:11 小阮 阅读(392) |
评论 (0) |
编辑 收藏
摘要: 对ditch里边的单词进行枚举, 需要预处理, 过滤掉不符合题意的单词.
/**//*ID: lorelei3TASK: lgameLANG: C++*/#include <fstream>#include <string>#include <memory.h>using namespace...
阅读全文
posted @
2011-01-30 11:23 小阮 阅读(208) |
评论 (0) |
编辑 收藏
第一问, 枚举地拿掉每个点u,看能否连通(dfs 到n),能连通的就是必需经过的点,对于点u 进行DFS,看会不会重复经过第一问中已经访问过的点,若都没有经过,则该u点符合第二问。

/**//*
ID: lorelei3
TASK: race3
LANG: C++
*/

#include <fstream>
#include <memory.h>

using namespace std;

const int MAX = 55;

ifstream fin("race3.in");
ofstream fout("race3.out");

int map[MAX][MAX];
int visited[MAX], ans1[MAX], ans2[MAX], cnt1, cnt2, n;


void input()
{
int i=0, in=0;

while(fin>>in && in!=-2)
{
int t=in;
int c = ++map[i][0];
map[i][c]=t;

while(fin>>t && t!=-2)
{
int c = ++map[i][0];
map[i][c]=t;
}
i++;
}
fin>>in;
n=i;
}


bool dfs1(int u)
{
if(u==n)
return true;


for(int i=1; i<=map[u][0]; ++i)
{
int v = map[u][i];

if(visited[v]==0)
{
visited[v]=1;
if(dfs1(v))
return true;
}
}
return false;
}

bool rep;

void dfs2(int u)
{
if(rep)
return;
if(visited[u]==2)
return;

visited[u]=2;

for(int i=1; i<=map[u][0]; ++i)
{
int v = map[u][i];

if(visited[v]==1)
{
rep=true;
return;
}
dfs2(v);
}
}


void solve()
{

for(int i=1; i<n; ++i)
{
memset(visited, 0, sizeof(visited));
visited[i]=1;
visited[0]=1;

if(!dfs1(0))
{
ans1[cnt1++] = i;
rep = false;
dfs2(i);
if(rep == false)
ans2[cnt2++] = i;
}
}
}


void output()
{
int i;
fout<<cnt1;


if(cnt1!=0)
{
fout<<" ";
for(i=0; i<cnt1-1; ++i)
fout<<ans1[i]<<" ";
fout<<ans1[cnt1-1];
}
fout<<endl;

fout<<cnt2;

if(cnt2!=0)
{
fout<<" ";
for(i=0; i<cnt2-1; ++i)
fout<<ans2[i]<<" ";
fout<<ans2[cnt2-1];
}
fout<<endl;
}


int main()
{

input();

solve();

output();

return 0;
}
posted @
2011-01-29 20:01 小阮 阅读(371) |
评论 (0) |
编辑 收藏
摘要: 做了一天. AC的速度还可以, 时间最长的 0.16s.1. 开始做之前,要确定下搜索顺序, 这个很关键. &...
阅读全文
posted @
2011-01-29 00:07 小阮 阅读(728) |
评论 (0) |
编辑 收藏
第一问,求最长下降子序列长度。
设a表示数据,len(i)=前i个数中最长下降子序列长度,状态转移方程 len (i)=max{len(j)+1}(j<i,a[j]>a[i]), 初始化f[i]=1 (i=0...n-1);
第二问:
对于c[i]=前i个数中最长下降子序列的个数,状态转移方程 c[i]=sigma(c[j]) (j<i,a[j]>a[i], len[i]==len[j]+1)
对于重复情况, 每一个可能重复的下降的子序列,它一定是a , b, b (a>b)的情况,开一个数组visited记录b是否出现过,若出现了,就不再计算。
状态转移方程: c[i]=sigma(c[j]) (j<i,a[j]>a[i], len[i]==len[j]+1),visited[j]=false)。
最后是高精度加法,我的版本是每一位存一个数,有待改进。
PS:这次代码风格有点变化。

/**//*
ID: lorelei3
TASK: buylow
LANG: C++
*/

#include <fstream>
#include <memory.h>

using namespace std;

const int MAXN = 5000;
const int MAXP = 50;


class HPNum
{
public:
int length;
int num[MAXP];


HPNum()
{
length=1;
memset(num,0,sizeof(num));
}


void plus(HPNum &p)
{
int len = length>p.length ? length : p.length;

for(int i=0; i<len; ++i)
{
num[i] = num[i]+p.num[i];

if(num[i]>=10)
{
num[i]-=10;
num[i+1]++;
}

}
if(num[len]>0)
len++;
length=len;
}
};

int n;
long maxlen;
long a[MAXN], len[MAXN];
bool visited[20000];
HPNum c[MAXN];

ifstream fin("buylow.in");
ofstream fout("buylow.out");


void input()
{
fin>>n;

for(int i=0; i<n; ++i)
{
fin>>a[i];
len[i]=1;
}
}


void dp()
{
int i,j;
maxlen=1;
for(i=1; i<n; ++i)

for(j=i-1; j>=0; --j)
{
if(a[i]<a[j] && len[i]<len[j]+1)
len[i] = len[j]+1;
if(maxlen<len[i])
maxlen = len[i];
}
for(i=0; i<n; ++i)

if(len[i]==1)
{
c[i].length=1;
c[i].num[0]=1;

}else
{
memset(visited, false, sizeof(visited));

for(j=i-1; j>=0; --j)
{

if(len[i]==len[j]+1 && !visited[a[j]] && a[i]<a[j])
{
c[i].plus(c[j]);
visited[a[j]]=true;
}
}
}
}


void output()
{
int i;
HPNum sum;
sum.length=1;
sum.num[0]=0;
memset(visited, false, sizeof(visited));
for(i=n-1; i>=0; --i)

if(len[i]==maxlen && !visited[a[i]])
{
sum.plus(c[i]);
visited[a[i]]=true;
}

fout<<maxlen<<" ";

for(i=sum.length-1; i>=0; --i)
fout<<sum.num[i];

fout<<endl;
}


int main()
{

input();

dp();

output();
return 0;
}

posted @
2011-01-27 00:59 小阮 阅读(460) |
评论 (0) |
编辑 收藏
参考了USACO上的提示:
1. 最大传动比率至少是最小的3倍。这个其实不用算出比率再判断,只要不满足s1[F]/s2[1]-s1[1]/s2[R]>=3的都剪掉 .
2. 用memcpy函数会更快.
3. 用插入排序对于规模较小的数据速度比较客观.

/**//*
ID: lorelei3
TASK: cowcycle
LANG: C++
*/

#include <fstream>
#include <memory.h>

using namespace std;

const int MAX = 100;

int F, R, F1, F2, R1, R2;
int s1[MAX], s2[MAX];
int ans1[MAX], ans2[MAX];
double rate[MAX*MAX], diff[MAX*MAX];
double minf = 0x7FFFFFFF;


void count()
{
int i,j,k=0;
double sum1=0, sum2=0, t=0;

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

for(j=1; j<=R; ++j)
{
t = (double)s1[i]/s2[j];
int p=++k;

while(rate[p-1]>=t)
{
rate[p] = rate[p-1];
p--;
}
rate[p] = t;
}

int cnt = F*R;

for(i=1; i<=cnt-1; ++i)
{
diff[i] = rate[i+1] - rate[i];
sum1 += diff[i];
}

double mean = sum1/(cnt-1);

for(i=1; i<=cnt-1; ++i)
sum2+=(diff[i]-mean)*(diff[i]-mean);

double var = sum2/cnt-1;


if(var<minf)
{
minf = var;
memcpy(ans1+1, s1+1, sizeof(int)*F);
memcpy(ans2+1, s2+1, sizeof(int)*R);
}
}


void dfs2(int k, int w)
{

if(k==R+1)
{
if(s1[F]*s2[R]<3*(s1[1]*s2[1]) )
return;
count();
return;

}else
{

for(int i=w; i<=R2-(R-k); ++i)
{
s2[k]=i;
dfs2(k+1, i+1);
}
}
}


void dfs1(int k, int w)
{

if(k==F+1)
{
dfs2(1, R1);
return;

}else
{

for(int i=w; i<=F2-(F-k); ++i)
{
s1[k]=i;
dfs1(k+1, i+1);
}
}
}


int main()
{

ifstream fin("cowcycle.in");
ofstream fout("cowcycle.out");

fin>>F>>R>>F1>>F2>>R1>>R2;

dfs1(1,F1);

int i;
for(i=1; i<=F-1; ++i)
fout<<ans1[i]<<" ";
fout<<ans1[F]<<endl;

for(i=1; i<=R-1; ++i)
fout<<ans2[i]<<" ";
fout<<ans2[R]<<endl;

return 0;
}
posted @
2011-01-26 12:03 小阮 阅读(266) |
评论 (0) |
编辑 收藏