第四届福建省大学生程序设计竞赛
FZU2140 Forever 0.5
题意:构造一些点使得满足一些条件
思路:把1个点放在(0,0)然后n-1点平均分在60度的圆弧上,这样也就是有n-1对点距离为1.0
因为是60°所以n-1里面有一对点距离是1.0
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<map> #include<cmath> #include<queue> #include<cstring> #include<set> #include<stack> #include<string> #include<ctime> #define LL long long #define maxn 50 #define MAX 700010 #define mod 1000000007 #define INF 0x3f3f3f3f #define eps 1e-5 using namespace std; const double pi = acos(-1.0) ; struct point { double x , y ; point(){}; point( double xx , double yy ) { x = xx ; y = yy ; } } ; point operator - ( point a , point b ) { return point( b.x-a.x , b.y-a.y ) ; } double cross( point a , point b ) { return a.x*b.y - a.y*b.x ; } int cmp( point a , point b ) { return a.y < b.y || a.y == b.y && a.x < b.x ; } double get_erea(point *p,int n) { double ans=0; for(int i = 1 ; i < n-1 ;i++) { ans += cross(p[i]-p[0],p[i+1]-p[0]) ; } return ans/2; } double len(point a,point b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } point Rotate(point a,double rad) { return point(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad)) ; } void out(point *p,int n ) { for( int i = 0 ; i < n ;i++) printf("%.6lf %.6lf\n",p[i].x,p[i].y) ; } bool check(point *p,int n ) { int ans=0,i,j; for( i = 0 ; i < n ;i++) for( j = i+1 ; j< n;j++) { double u = len(p[i],p[j]) ; if(fabs(u-1.0) <eps)ans++; else if(u>1.0) return false; } if(ans==n) return true; return false; } int main() { int T,case1=0,n ; int i,j,k,u,v,ans; point p[110],aa ; double rad; cin >> T ; while(T--) { scanf("%d",&n) ; if(n<=3) { puts("No"); continue ; } p[0].x=0; p[0].y=0; p[1].x=1; p[1].y=0; aa=p[1] ; rad=pi/3; rad /= (n-2); for(i = 2 ; i < n ;i++) { aa=Rotate(aa,rad) ; p[i]=aa; } double ans=get_erea(p,n) ; // printf("%.6lf\n",ans) ; // cout<<check(p,n) << endl; if(ans+eps>=0.5&&ans<=0.75) { puts("Yes") ; out(p,n) ; } else puts("No") ; } return 0; }
FZU2141 Sub-Bipartite Graph
题意:取出原图的一个子图,这个图是二分图,有至少m/2条边
思路:设二分图的两个部分是A,B,开始所有点在B里面。每次寻找最多度数(去掉A里面的点)的一个点放到A里面,然后判断是否满足要求
没有就继续上面过程。
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<map> #include<cmath> #include<queue> #include<cstring> #include<set> #include<stack> #include<string> #include<ctime> #define LL long long #define u64 unsigned long long #define maxn 100010 #define mod 1000000007 #define INF 1000010 #define eps 1e-5 using namespace std; vector<int>qe[110],ans ; int in[110]; bool vi[110] ,hehe[110]; int find(int n) { memset(in,0,sizeof(in)) ; for(int i = 1 ; i <= n ;i++)if(!hehe[i]) { for(int j = 0 ; j < qe[i].size();j++) { int v = qe[i][j] ; if(!hehe[v])in[i]++ ; } } int id=INF,Max=0; for( int i = 1 ; i <= n;i++)if(!hehe[i]) { if(Max<in[i]) { Max=in[i] ; id=i; } } return id; } bool check(int n,int m) { int cnt=0; for(int i = 1 ; i <= n ;i++)if(hehe[i]) { for( int j = 0 ; j < qe[i].size();j++) { int v = qe[i][j] ; if(!hehe[v])cnt++; } } if(cnt>=m/2) return true; return false; } int main() { int i,j,n,m,k; int u,v,len ,cnt ; int T; cin >> T ; while(T--) { scanf("%d%d",&n,&m) ; ans.clear(); for( i = 1 ; i <= n ;i++) { hehe[i]=false; qe[i].clear(); } for( i = 1 ; i <= m;i++) { scanf("%d%d",&u,&v) ; qe[u].push_back(v) ; qe[v].push_back(u) ; } len=0; while(true) { k=find(n) ; if(k==INF) break ; hehe[k]=true; ans.push_back(k) ; if(check(n,m)) break ; } cout << ans.size() ; for( i = 0 ; i < ans.size();i++) cout << " " << ans[i] ; puts("") ; cout << n-ans.size() ; for( i = 1 ; i <= n ;i++) { if(!hehe[i]){ printf(" %d",i) ; } } puts("") ; } return 0 ; }
FZU2143 Board Game
题意:不好说
思路:棋盘模型,用最小费用流做。
(a-b)^2 = a*a-2*a*b+b*b,b是常数,忽略。
对于偶数的格子,源点连向它k条边,第i条边的流量为1,花费是 i-1增加到i的代价
也就是 2*i-1-2*b
对于奇数的格子也是一样,不过是它连向汇点
然后奇数格子向相邻的格子连边,代价 0,流量INF
在跑最小费用流的时候,如果dis[t] >= 0 那么就可以退出了,
因为如果加上,那么总的代价就会增加
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<map> #include<cmath> #include<queue> #include<cstring> #include<set> #include<stack> #include<string> #include<ctime> #define LL long long #define u64 unsigned long long #define maxn 100010 #define mod 1000000007 #define INF 1000010 #define eps 1e-5 using namespace std; struct node { int u,v,cap,flow,cost,next; }edge[maxn]; int inf=INF,dis[1010],pre[10010],top; int head[10010]; bool vis[10010] ; void add(int u,int v,int cap,int flow,int cost) { edge[top].u = u ; edge[top].v = v ; edge[top].cap = cap ; edge[top].flow = flow ; edge[top].cost = cost ; edge[top].next = head[u] ; head[u]=top++ ; } void Unit(int u,int v,int cap,int cost ) { //cout<<u<<" "<<v<<endl; add(u,v,cap,0,cost); add(v,u,0,0,-cost) ; } void init() { memset(head,-1,sizeof(head)) ; top=0; } bool spfa(int s, int t) { queue<int>q; // why for (int i = 0; i < 1010; i++) { dis[i] = inf; vis[i] = false; pre[i] = -1; } dis[s] = 0; vis[s] = true; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; if (edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost ) { dis[v] = dis[u] + edge[i].cost; pre[v] = i; if (!vis[v]) { vis[v] = true; q.push(v); } } } } if(dis[t]>=0) return false;////////././.? if (pre[t] == -1)return false; else return true; } int minCost(int s, int t) { int flow = 0; int cost = 0; while (spfa(s, t)) { int Min = inf; for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].v]) { if (Min > edge[i].cap - edge[i].flow) Min = edge[i].cap - edge[i].flow; } for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].v]) { edge[i].flow += Min; edge[i ^ 1].flow -= Min; cost += edge[i].cost * Min; } flow += Min; } // cout<<cost<<"========"<<endl; return cost; } int mat[10][10] ,map1[10][10]; int main() { int n,m,i,j,k,ans,s,e; int T,case1=0,cnt; cin >> T ; while(T--) { scanf("%d%d%d",&n,&m,&k) ; init(); ans=cnt=0; for( i = 0 ;i < n ;i++) for( j = 0 ; j < m ;j++){ scanf("%d",&mat[i][j]) ; ans += mat[i][j]*mat[i][j] ; map1[i][j]=++cnt ; } s = 0 ; e = ++cnt ; for( i = 0 ; i < n ;i++) for( j = 0 ; j < m ;j++) { for( int u = 1 ; u <= k ;u++) { if(i%2==j%2) Unit(s,map1[i][j],1,2*u-1-2*mat[i][j]) ; else Unit(map1[i][j],e,1,2*u-1-2*mat[i][j]) ; } if(i%2==j%2) { if(i<n-1)Unit(map1[i][j],map1[i+1][j],INF,0) ; if(j<m-1)Unit(map1[i][j],map1[i][j+1],INF,0) ; if(i>=1)Unit(map1[i][j],map1[i-1][j],INF,0) ; if(j>=1)Unit(map1[i][j],map1[i][j-1],INF,0) ; } } printf("Case %d: %d\n",++case1,ans+minCost(s,e)) ; } return 0 ; }
FZU 2144 Shooting Game
题意:有n个物体,它出现在一些地方,有一个飞行的方向,速度为1;一个人可以一次袭击把圆里面的所以物体击落
思路:问最少多少次袭击,可以把最多的物品击落。
联立球的方程和直线方程,可以解出 进去时间和出来时间,也就是一个居间
这样就是用最少的点覆盖所有线段问题
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<map> #include<cmath> #include<queue> #include<cstring> #include<set> #include<stack> #include<string> #include<ctime> #define LL long long #define u64 unsigned long long #define maxn 100010 #define mod 1000000007 #define INF 0x3f3f3f3f #define eps 1e-6 using namespace std; struct node { double L,R ; bool operator<(const node&s) const { return R < s.R ; } }qe[maxn] ; void getnumq(int& x){ char ch=getchar(); bool mk=0; x = 0; while(ch<48 || ch>57){ if(ch=='-') mk=1; ch=getchar(); } while(ch>=48 && ch<=57){ x = x*10+ch-48; ch = getchar(); } if(mk) x=-x; } void getnum(double& x){ int y; getnumq(y); x = y*1.0; } int solve(int m) { sort(qe,qe+m) ; int ans=0,j; for( int i = 0 ; i < m ;i++) { ans++ ; j=i+1; while(j<m && qe[j].L <=qe[i].R ) { j++ ; } i = j-1; } return ans; } int main() { int i,n,m,j,len,T,case1=0; double ax,ay,az,dx,dy,dz ; double r,a,b,c,d; cin >> T ; while(T--) { scanf("%d%lf",&n,&r) ; len=0; for( j = 1 ; j <= n ;j++ ) { getnum(ax); getnum(ay); getnum(az); getnum(dx); getnum(dy); getnum(dz); a = dx*dx+dy*dy+dz*dz; b = 2*(ax*dx+ay*dy+az*dz); c = ax*ax+ay*ay+az*az-r*r; d = b*b-4*a*c; if(d<0)continue; qe[len].L = (b*(-1)-sqrt(d))/(a*2); qe[len].R = (b*(-1)+sqrt(d))/(a*2); if(qe[len].L<0 && qe[len].R<0)continue; len++; } printf("Case %d: %d %d\n",++case1,len,solve(len)) ; } return 0 ; }
FZU 2148 Moon Game
题意:给出n个点,问组成凸四边形的组数
思路:数据很小,枚举。然后判断是否是凸的,
判断大概可以用凸包了......
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<map> #include<cmath> #include<queue> #include<cstring> #include<set> #include<stack> #include<string> #include<ctime> #define LL long long #define maxn 50 #define MAX 700010 #define mod 1000000007 #define INF 0x3f3f3f3f #define eps 1e-6 using namespace std; struct point { int x , y ; point(){}; point( int xx , int yy ) { x = xx ; y = yy ; } } ; point qe[maxn] , p[maxn] ; point operator - ( point a , point b ) { return point( b.x-a.x , b.y-a.y ) ; } int cross( point a , point b ) { return a.x*b.y - a.y*b.x ; } int cmp( point a , point b ) { return a.y < b.y || a.y == b.y && a.x < b.x ; } int Get( int n ) { sort(qe,qe+n,cmp) ; int m = 1 , i , k; if( n == 0 ) return 0 ;p[0] = qe[0] ; if( n == 1 ) return 1 ;p[1] = qe[1] ; if( n == 2 ) return 2 ;p[2] = qe[2] ; for( i = 2 ; i < n ;i++) { while( m && cross( p[m]-p[m-1] , qe[i] - p[m-1] ) <= 0 )m-- ; p[++m] = qe[i] ; } k = m ;p[++m] = qe[n-2] ; for( i = n-3 ; i >= 0 ; i-- ) { while( m > k && cross( p[m]-p[m-1] , qe[i]-p[m-1] ) <= 0 )m-- ; p[++m] = qe[i] ; } return m ; } int xx[maxn],yy[maxn] ; int main() { int T,case1=0,n ; int i,j,k,u,v,ans; cin >> T ; while(T--) { scanf("%d",&n) ; for( i = 1 ; i <= n ;i++) scanf("%d%d",&xx[i],&yy[i]) ; ans=0; for( i=1 ; i<= n ;i++) for(j=i+1;j<=n;j++) for(u=j+1;u<=n;u++) for(v=u+1;v<=n;v++) { qe[0].x=xx[i] ;qe[0].y=yy[i] ; qe[1].x=xx[j] ;qe[1].y=yy[j] ; qe[2].x=xx[u] ;qe[2].y=yy[u] ; qe[3].x=xx[v] ;qe[3].y=yy[v] ; k = Get(4) ; //cout<<k<<endl; if(k==4)ans++; } printf("Case %d: %d\n",++case1,ans) ; } return 0; }
FZU 2150 Fire Game
题意:、
思路:枚举两点,然后dfs;
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<map> #include<cmath> #include<queue> #include<cstring> #include<set> #include<stack> #include<string> #include<ctime> #define LL long long #define maxn 20 #define MAX 700010 #define mod 1000000007 #define INF 0x3f3f3f3f #define eps 1e-6 using namespace std; char mat[maxn][maxn] ; int time1[maxn][maxn] ; int n,m; void dfs(int x,int y,int t) { time1[x][y]= t ; if(x>1&&mat[x-1][y]=='#'&&time1[x-1][y]>t+1) { dfs(x-1,y,t+1); } if(y>1&&mat[x][y-1]=='#'&&time1[x][y-1]>t+1) { dfs(x,y-1,t+1); } if(x<n&&mat[x+1][y]=='#'&&time1[x+1][y]>t+1) { dfs(x+1,y,t+1); } if(y<m&&mat[x][y+1]=='#'&&time1[x][y+1]>t+1) { dfs(x,y+1,t+1); } } int solve(int s1,int e1,int s2,int e2) { memset(time1,INF,sizeof(time1)) ; dfs(s1,e1,0) ; dfs(s2,e2,0) ; int ans=-1 ; for(int i = 1 ; i <= n ;i++) for(int j = 1 ; j <= m ;j++)if(mat[i][j]=='#') { ans=max(ans,time1[i][j]) ; } return ans; } int getans() { int ans=INF,t; for(int i = 1 ; i <= n ;i++) for(int j = 1 ; j <= m ;j++)if(mat[i][j]=='#') { for(int k = i ; k <= n ;k++) for(int kk = 1 ; kk <= m ;kk++)if(mat[k][kk]=='#') { int t = solve(i,j,k,kk) ; if(t==-1) t = INF ; ans=min(ans,t) ; } } if(ans==INF) return -1; return ans; } int main() { int T,case1=0 ; int i,j,k,ans; cin >> T ; while(T--) { scanf("%d%d",&n,&m) ; for( i = 1 ; i <= n ;i++) scanf("%s",mat[i]+1) ; printf("Case %d: %d\n",++case1,getans()) ; } return 0; }