本篇文章都是复制粘贴的…不想自己做
D. Shortest Cycle
题意:一个环至少有 3 3 3个点, a a a& b ! b! b!= 0 0 0 的两个点间有一条边,求最小环
题解:
f l o y e d floyed floyed求解最小环 O ( n 3 ) O(n^3) O(n3)
emmm想到了范围问题,然后就使劲考虑怎么建环,emmm赛后发现有现成的模板…其实就是DP。
#include
#define mp make_pair
#define se second
#define fi first
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;
const int N=5e5+10;
const int MAXN=20010;
const int INF=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const double eps=0.0000001;
const ll mod=1e9+7;
int n,m,x,y,z,k,cnt,t,len;
ll a[N];
ll dp[305][305],ans[305][305];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
if(n>=300)
return printf("3\n"),0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
ans[i][j]=dp[i][j]=INF;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j) continue;
if((a[i]&a[j])!=0) dp[i][j]=ans[i][j]=1;
}
}
ll cnt=INF;
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j||j==k||k==i) continue;
cnt=min(cnt,dp[i][k]+dp[k][j]+ans[i][j]);
ans[i][j]=min(ans[i][j],ans[i][k]+ans[k][j]);
}
}
}
if(cnt!=INF)
printf("%lld\n",cnt);
else printf("-1\n");
}
E. Let’s Go Rolling!
题意:
数轴上有 n n n个质点,第 i i i个质点的坐标为 x i x_i xi,花费为 c i c_i ci,现在要选择其中一些点固定,代价为这些点的花费,固定的点不动,不固定的点会向左移动直至遇到固定的点,代价是这两点的距离,如果左边没有固定的点则花费为正无穷,问最小代价。
题解:动态规划
d p [ i ] [ j ] dp[i][j] dp[i][j] i i i 表示第 i i i个小球; j j j 代表被固定的隔板;
#include
#define mp make_pair
#define se second
#define fi first
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;
const int N=5e5+10;
const int MAXN=20010;
const int INF=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const double eps=0.0000001;
const ll mod=1e9+7;
ll n,m,x,y,z,k,cnt,t,len;
ll dp[3010][3010];
struct node
{
ll x,y;
}a[5000];
bool cmp(node a,node b)
{
return a.x<b.x;
}
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&a[i].x,&a[i].y);
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dp[i][j]=INF64;
dp[1][1]=a[1].y;
for(int i=1;i<n;i++)
{
for(int j=1;j<=i;j++)
{
dp[i+1][j]=min(dp[i+1][j],dp[i][j]+a[i+1].x-a[j].x);
dp[i+1][i+1]=min(dp[i+1][i+1],dp[i][j]+a[i+1].y);
}
}
ll ans=INF64;
for(int i=1;i<=n;i++)
ans=min(ans,dp[n][i]);
printf("%lld\n",ans);
}
B - Triangles
题意:判断两个三角形的关系
题解:详细题解
三角形的叉积
我特别想知道谁给我的勇气刚这道题…关键还没刚出来…
#include
#include
#include
#include
#define eps 1e-8
#define zero(x) (((x)>0?(x):(-x))
using namespace std;
struct point{double x,y;};
struct triangle{point a,b,c;};
///计算叉积
/**
设向量A=p1-p0,B=p2-p0;
| i j k |
AxB=| p1.x-p0.x p1.y-p0.y 0 |
| p2.x-p0.x p2.y-p0.y 0 |
*/
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);
}
///判断三点共线
/**
若三点共线 设向量A=p1-p0,B=p2-p0;
|AxB|=|A||B|sin,又三点共线,所以=0,所以|AxB|=0;
*/
int dots_inline(point p1,point p2,point p3){
return zero(xmult(p1,p2,p3));
}
///判断两点在线段同侧
/**
设向量 A=l2-l1,B=p2-l1,C=p1-l1;
由右手定则可以得出,若p1,p2两点同侧,则|AxB|与|AxC|同正负;
若p1或p2在线段上,则|AxC|或|AxB|等于0
*/
int same_side(point p1,point p2,point l1,point l2){
return xmult(l1,p1,l2) * xmult(l1,p2,l2) > eps;
}
///判断点是否在线上,包括端点
/**
1.先判三点共线;
2.再判点是否在线段上,如果在,则两个端点的横坐标与该点的横坐标(纵坐标)之差的积小于或者等于零;
*/
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.先判是否共线,如果不共线,看其中一条边的两个端点是否在另一条线段的两侧;
2.判断点是否在线段上;
*/
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);
}
///计算面积
/**
S=|AxB|/2;
*/
double area_triangle(point p1,point p2,point p3){
return fabs(xmult(p1,p2,p3))/2;
}
///判断点是否包含在三角形内部,包括三条边上
/**
大三角形与三个小三角形的面积之差是否为零
*/
int dot_triangle_in(triangle p1,point p0){
return fabs(area_triangle(p1.a,p1.b,p1.c)-area_triangle(p1.a,p1.b,p0)-area_triangle(p1.a,p0,p1.c)-area_triangle(p0,p1.b,p1.c))<eps;
}
void solve_question(){
point a[3],b[3];
triangle A,B;
for(int i=0;i<3;i++)
cin >> a[i].x >> a[i].y;
for(int i=0;i<3;i++)
cin >> b[i].x >> b[i].y;
A = (triangle){a[0],a[1],a[2]};
B = (triangle){b[0],b[1],b[2]};
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
if(intersect_in(a[i],a[(i+1)%3],b[j],b[(j+1)%3])) { printf("intersect\n");return;}
if(dot_triangle_in(A,b[0]) || dot_triangle_in(B,a[0]))
printf("contain\n");
else
printf("disjoint\n");
}
int main(){
int T;
scanf("%d",&T);
while(T--){
solve_question();
}
}
#include
using namespace std;
char MAP[5][5];
bool judge(char c)//判断c是否已经成功
{
if(MAP[1][1]==c&&MAP[1][2]==c&&MAP[1][3]==c) return 1;
if(MAP[2][1]==c&&MAP[2][2]==c&&MAP[2][3]==c) return 1;
if(MAP[3][1]==c&&MAP[3][2]==c&&MAP[3][3]==c) return 1;
if(MAP[1][1]==c&&MAP[2][1]==c&&MAP[3][1]==c) return 1;
if(MAP[1][2]==c&&MAP[2][2]==c&&MAP[3][2]==c) return 1;
if(MAP[1][3]==c&&MAP[2][3]==c&&MAP[3][3]==c) return 1;
if(MAP[1][1]==c&&MAP[2][2]==c&&MAP[3][3]==c) return 1;
if(MAP[1][3]==c&&MAP[2][2]==c&&MAP[3][1]==c) return 1;
return 0;
}
bool win(char c)//Kim是否能有两个以上赢面
{
if(judge(c))
return 1;
int num=0;
for(int i=1; i<=3; i++)
{
for(int j=1; j<=3; j++)
{
if(MAP[i][j]=='.')
{
MAP[i][j]=c;
if(judge(c))
num++;
MAP[i][j]='.';
}
}
}
if(num>=2)
return 1;
return 0;
}
bool win1(char c)//对方是否能1步走赢
{
if(judge(c))
return 1;
int num=0;
for(int i=1; i<=3; i++)
{
for(int j=1; j<=3; j++)
{
if(MAP[i][j]=='.')
{
MAP[i][j]=c;
if(judge(c))
num++;
MAP[i][j]='.';
}
}
}
if(num)
return 1;
return 0;
}
int main()
{
std::ios::sync_with_stdio(0);
int t;
char c1,c2;
cin>>t;
while(t--)
{
for(int i=1; i<=3; i++)
{
for(int j=1; j<=3; j++)
{
cin>>MAP[i][j];
}
}
cin>>c1;
if(c1=='x')
c2='o';
else
c2='x';
int flag=0;
for(int i=1; i<=3; i++)
{
for(int j=1; j<=3; j++)
{
if(MAP[i][j]=='.')//枚举所有Kim可以放的点
{
MAP[i][j]=c1;//走该步的话,现在该c2走了
if(win(c1)&&!win1(c2))//一定要c2一步赢不了的情况下c1一定要有至少2个赢面才算真正的赢
{
flag=1;
goto label;
}
MAP[i][j]='.';//恢复原状
}
}
}
label:
if(flag)
cout<<"Kim win!"<<endl;
else
cout<<"Cannot win!"<<endl;
}
return 0;
}