Regionals 2012 :: HangZhou

题目传送门
排行榜

一个人做了12年北大出的题,自己还是太弱了,图论的知识忘光光,最小生成树裸题写不来,Dijkstra TLE不知道用SPFA。

简单几何(点到线段的距离) + 三分 B Stealing a Cake

题意:圆外一个点先到圆再到矩形的最短距离。

分析:由于圆在[0, PI]和[PI, PI*2]上是单峰函数,用三分求极值,应该在[0,PI*2]上也算单峰函数吧。

/************************************************
* Author        :Running_Time
* Created Time  :2015/11/7 星期六 17:24:32
* File Name     :B_2.cpp
 ************************************************/

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double EPS = 1e-10;
const double PI = acos (-1.0);
int dcmp(double x)  {       //三态函数,减少精度问题
    if (fabs (x) < EPS) return 0;
    else    return x < 0 ? -1 : 1;
}
struct Point    {       //点的定义
    double x, y;
    Point () {}
    Point (double x, double y) : x (x), y (y) {}
    Point operator + (const Point &r) const {       //向量加法
        return Point (x + r.x, y + r.y);
    }
    Point operator - (const Point &r) const {       //向量减法
        return Point (x - r.x, y - r.y);
    }
    Point operator * (double p) const {       //向量乘以标量
        return Point (x * p, y * p);
    }
    Point operator / (double p) const {       //向量除以标量
        return Point (x / p, y / p);
    }
    bool operator < (const Point &r) const {       //点的坐标排序
        return x < r.x || (x == r.x && y < r.y);
    }
    bool operator == (const Point &r) const {       //判断同一个点
        return dcmp (x - r.x) == 0 && dcmp (y - r.y) == 0;
    }
};
typedef Point Vector;       //向量的定义
Point read_point(void)   {      //点的读入
    double x, y;
    scanf ("%lf%lf", &x, &y);
    return Point (x, y);
}
double dot(Vector A, Vector B)  {       //向量点积
    return A.x * B.x + A.y * B.y;
}
double cross(Vector A, Vector B)    {       //向量叉积
    return A.x * B.y - A.y * B.x;
}
Vector rotate(Vector A, double rad) {
    return Vector (A.x * cos (rad) - A.y * sin (rad), A.x * sin (rad) + A.y * cos (rad));
}
double length(Vector A) {
    return sqrt (dot (A, A));
}
double angle(Vector A, Vector B)    {       //向量转角,逆时针,点积
    return acos (dot (A, B) / length (A) / length (B));
}
double point_to_seg(Point p, Point a, Point b)  {
    if (a == b) return length (p - a);
    Vector V1 = b - a, V2 = p - a, V3 = p - b;
    if (dcmp (dot (V1, V2)) < 0)    return length (V2);
    else if (dcmp (dot (V1, V3)) > 0)   return length (V3);
    else    return fabs (cross (V1, V2)) / length (V1);
}

struct Circle   {
    Point c;
    double r;
    Circle () {}
    Circle (Point c, double r) : c (c), r (r) {}
    Point point(double a)   {
        return Point (c.x + cos (a) * r, c.y + sin (a) * r);
    }
};

Point s, a, b, c, d;
Circle C;

double cal_dis(double rad)  {
    Point p = C.point (rad);
    double dis1 = length (s - p);
    double dis2 = 1e9;
    dis2 = min (dis2, point_to_seg (p, a, b));
    dis2 = min (dis2, point_to_seg (p, b, c));
    dis2 = min (dis2, point_to_seg (p, c, d));
    dis2 = min (dis2, point_to_seg (p, d, a));
    return dis1 + dis2;
}

int main(void)    {
    double x, y, r, x2, y2;
    while (scanf ("%lf%lf", &x, &y) == 2)	{
		if (dcmp (x) == 0 && dcmp (y) == 0)	break;
		s = Point (x, y);
		scanf ("%lf%lf%lf", &x, &y, &r);
		C = Circle (Circle (Point (x, y), r));
        scanf ("%lf%lf%lf%lf", &x, &y, &x2, &y2);
        a = Point (min (x, x2), max (y, y2));
        b = Point (min (x, x2), min (y, y2));
        c = Point (max (x, x2), min (y, y2));
        d = Point (max (x, x2), max (y, y2));
        Vector V[2];
        int cnt = point_cir_tan (s, C, V);
        double l = angle (Vector (1, 0), V[0]), r = angle (Vector (1, 0), V[1]);
        if (l > r)  swap (l, r);
        while (r - l > EPS) {
            double mid = (l + r) / 2;
            double lmid = (l + mid) / 2;
            double rmid = (r + mid) / 2;
            double res1 = cal_dis (lmid),
                   res2 = cal_dis (rmid);
            if (res1 < res2)    {
                r = rmid;
            }
            else    l = lmid;
        }
        printf ("%.2f\n", cal_dis (l));
    }
    return 0;
}

  

SPFA/BFS H Friend Chains

题意:就是求任意两点的最短路的最大值

分析:Floyd O(n^3)绝对超时,我想了Dijkstra,O (V * (VlogE + V),后来用了SPFA倒是勉勉强强过了,对Dijkstra无爱了。杭电discuss里有人写了最快的解法,类似于求树的直径,两边BFS。问题是第一次找最远的点可能有多个,要选择度数最小的,否则度数多了,从那个点出发到某些点并不是最远的,也就不是直径。

SPFA

#include <bits/stdc++.h>
using namespace std;

const int N = 1e3 + 10;
const int E = 2e4 + 10;
const int INF = 0x3f3f3f3f;
struct Edge	{
	int v, w, nex;
	Edge () {}
    Edge (int v, double w, int nex) : v (v), w (w), nex (nex) {}
}edge[E];
int head[N];
bool vis[N];
int d[N];
int n, m, e;

void init(void)	{
	memset (head, -1, sizeof (head));
	e = 0;
}
void add_edge(int u, int v, int w)	{
    edge[e] = Edge (v, w, head[u]);
    head[u] = e++;
}

void SPFA(int s)    {
    for (int i=1; i<=n; ++i)    {
        vis[i] = false; d[i] = INF;
    }
    vis[s] = true;  d[s] = 0;
    queue<int> Q;   Q.push (s);
    while (!Q.empty ()) {
        int u = Q.front (); Q.pop ();
        vis[u] = false;
        for (int i=head[u]; ~i; i=edge[i].nex)  {
            int v = edge[i].v, w = edge[i].w;
            if (d[v] > d[u] + w)    {
                d[v] = d[u] + w;
                if (!vis[v])    {
                    vis[v] = true;  Q.push (v);
                }
            }
        }
    }
}

map<string, int> id;
char str1[11], str2[11];

int main(void)	{
	while (scanf ("%d", &n) == 1)	{
		if (!n)	break;
		id.clear ();
		for (int i=1; i<=n; ++i)	{
            scanf ("%s", &str1);
            id[str1] = i;
		}
		init ();
		scanf ("%d", &m);
		for (int i=1; i<=m; ++i)	{
			scanf ("%s%s", &str1, &str2);
            if (id[str1] == id[str2])	continue;
			add_edge (id[str1], id[str2], 1);
			add_edge (id[str2], id[str1], 1);
		}

		int ans = 0;
		for (int i=1; i<=n; ++i)	{
		    SPFA (i);
            for (int j=1; j<=n; ++j)    {
                if (d[j] == INF)    {
                    ans = -1;   break;
                }
                if (ans < d[j]) ans = d[j];
            }
            if (ans == -1)  break;
        }
		printf ("%d\n", ans);
	}

	return 0;
}

BFS

/************************************************
* Author        :Running_Time
* Created Time  :2015/11/7 星期六 16:16:25
* File Name     :H_2.cpp
 ************************************************/

#include <bits/stdc++.h>
using namespace std;

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int N = 1e3 + 10;
const int E = 2e4 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double EPS = 1e-10;
const double PI = acos (-1.0);
struct Edge	{
	int v, w, nex;
	Edge () {}
    Edge (int v, int w, int nex) : v (v), w (w), nex (nex) {}
}edge[E];
int head[N], d[N], deg[N];
bool vis[N];
int n, m, e;

void init(void)	{
	memset (head, -1, sizeof (head));
    memset (deg, 0, sizeof (deg));
	e = 0;
}
void add_edge(int u, int v, int w)	{
    edge[e] = Edge (v, w, head[u]);
    head[u] = e++;
}

int BFS(int s) {
    for (int i=1; i<=n; ++i)    {
        d[i] = (i == s) ? 0 : INF;
        vis[i] = (i == s) ? true : false;
    }
    queue<int> Q;   Q.push (s);
    int idx = 0, mx = 0;
    while (!Q.empty ()) {
        int u = Q.front (); Q.pop ();
        for (int i=head[u]; ~i; i=edge[i].nex)  {
            int v = edge[i].v, w = edge[i].w;
            if (vis[v]) continue;
            if (d[v] > d[u] + w)    {
                d[v] = d[u] + w;
                vis[v] = true;  Q.push (v);
            }
            if (d[v] > mx || (d[v] == mx && deg[v] < deg[idx]))  {
                mx = d[v];  idx = v;
            }
        }
    }
    return idx;
}
map<string, int> id;
char str1[11], str2[11];

int main(void)	{
	while (scanf ("%d", &n) == 1)	{
		if (!n)	break;
		id.clear ();
		for (int i=1; i<=n; ++i)	{
            scanf ("%s", &str1);
            id[str1] = i;
		}
		init ();
		scanf ("%d", &m);
		for (int i=1; i<=m; ++i)	{
			scanf ("%s%s", &str1, &str2);
            if (id[str1] == id[str2])	continue;
			add_edge (id[str1], id[str2], 1);
			add_edge (id[str2], id[str1], 1);
		    deg[id[str1]]++;    deg[id[str2]]++;
        }
		int ans = 0;
        int idx = BFS (1);
        ans = d[BFS (idx)];
        for (int i=1; i<=n; ++i)    {
            if (d[i] == INF)    {
                ans = -1;   break;
            }
        }
        printf ("%d\n", ans);
	}

	return 0;
}

  

I The Power of Xiangqi

比赛前走了一盘象棋,竟然就碰到了关于象棋的题目。

状态压缩+枚举 J Scaring the Birds

题意:有几个点可以放稻草人,问最少放几个稻草人才能保护所以稻草

分析:没什么陷阱吧,主要看样例的R的范围有些纠结,放稻草人的点没有稻草的。只要状压枚举要放的数量和位置就可以了。

#include <bits/stdc++.h>
using namespace std;

const int N = 55;
const int INF = 0x3f3f3f3f;
struct Point	{
    int x, y, r, step;
    Point () {}
    Point (int x, int y, int step) : x (x), y (y), step (step) {}
}p[11];
int n, m;
int a[N][N];
bool vis[N][N];
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};

void map_init(void)	{
    for (int i=1; i<=n; ++i)	{
        for (int j=1; j<=n; ++j)	a[i][j] = 0;
    }
    for (int i=0; i<m; ++i)	{
        a[p[i].x][p[i].y] = 1;
    }
}

bool judge(void)	{
    for (int i=1; i<=n; ++i)	{
        for (int j=1; j<=n; ++j)	{
            if (!a[i][j])	return false;
        }
    }
    return true;
}

bool check(int x, int y)	{
    if (x < 1 || x > n || y < 1 || y > n || vis[x][y])	return false;
    else	return true;
}

void BFS(int u)	{
    int R = p[u].r;	vis[p[u].x][p[u].y] = true;
    queue<Point> Q;	Q.push (Point (p[u].x, p[u].y, 0));
    while (!Q.empty ())	{
        Point r = Q.front ();	Q.pop ();
        if (r.step > R)	continue;
        a[r.x][r.y] = 1;
        for (int i=0; i<4; ++i)	{
            int tx = r.x + dx[i], ty = r.y + dy[i];
            if (!check (tx, ty))	continue;
            vis[tx][ty] = true;
            Q.push (Point (tx, ty, r.step + 1));
        }
    }
}

int main(void)	{
    while (scanf ("%d", &n) == 1)	{
        if (!n)	break;
        scanf ("%d", &m);
        for (int i=0; i<m; ++i)	{
            scanf ("%d%d", &p[i].x, &p[i].y);
        }
        for (int i=0; i<m; ++i)	{
            scanf ("%d", &p[i].r);
        }
        int S = 1 << m;
        int ans = INF;
        for (int i=0; i<S; ++i)	{
            int num = __builtin_popcount (i);
            map_init ();
            for (int j=0; j<m; ++j)	{
                if (i & (1 << j))	{
                    memset (vis, false, sizeof (vis));
                    BFS (j);
                }
            }
            if (!judge ())	continue;
            ans = min (ans, num);
        }
        if (ans == INF)	puts ("-1");
        else	printf ("%d\n", ans);
    }

    return 0;
}

  

最小生成树 K Outlets

题意:求最小生成树,限制是p和q一定要有边连

分析:作为第二水的题目我竟然不会写,kruskal的方法前先将p和q连上边就行了,或者Prim在p到q的距离变为0(优先出队列),然后再加回去。

Kruskal

#include <bits/stdc++.h>
using namespace std;

const int N = 55;
const int E = N * N;
const double INF = 1e9;
struct Edge	{
	int u, v;
	double w;
	Edge () {}
    Edge (int u, int v, double w) : u (u), v (v), w (w) {}
    bool operator < (const Edge &r) const {
		return w < r.w;
    }
}edge[E];
struct UF   {
    int rt[N], rk[N];
    void init(void) {
        memset (rt, -1, sizeof (rt));
        memset (rk, 0, sizeof (rk));
    }
    int Find(int x) {
        return rt[x] == -1 ? x : rt[x] = Find (rt[x]);
    }
    void Union(int x, int y)    {
        x = Find (x);   y = Find (y);
        if (x == y) return ;
        if (rk[x] > rk[y])  {
            rt[y] = x;  rk[x] += rk[y];
        }
        else    {
            rt[x] = y;  rk[y] += rk[x];
        }
    }
}uf;
int x[N], y[N];
int tot;

double sqr(int x, int y)	{
	return (double) (x * x + y * y);
}
double cal_dis(int i, int j)	{
	return sqrt (sqr (x[i] - x[j], y[i] - y[j]));
}

void add_edge(int u, int v, double w)	{
    edge[tot++] = Edge (u, v, w);
}

int p, q;

int main(void)	{
	int n;
	while (scanf ("%d", &n) == 1)	{
		if (!n)	break;
		scanf ("%d%d", &p, &q);
		if (p > q)  swap (p, q);
        for (int i=1; i<=n; ++i)	{
            scanf ("%d%d", &x[i], &y[i]);
		}
		uf.init (); tot = 0;
		double ans = cal_dis (p, q);
        uf.rt[p] = q;
        for (int i=1; i<=n; ++i)	{
			for (int j=i+1; j<=n; ++j)	{
				add_edge (i, j, cal_dis (i, j));
            }
		}
        sort (edge, edge+tot);
        for (int i=0; i<tot; ++i)   {
            int u = edge[i].u, v = edge[i].v;
            double w = edge[i].w;
            u = uf.Find (u);    v = uf.Find (v);
            if (u == v) continue;
            ans += w;
            uf.Union (u, v);
        }
		printf ("%.2f\n", ans);
	}

	return 0;
}

Prim

#include <bits/stdc++.h>
using namespace std;

const int N = 55;
const int E = N * N;
const double INF = 1e9;
struct Edge	{
	int v, nex;
	double w;
	Edge () {}
    Edge (int v, double w, int nex) : v (v), w (w), nex (nex) {}
    bool operator < (const Edge &r) const {
		return w > r.w;
    }
}edge[E];
int head[N];
bool vis[N];
double d[N];
int x[N], y[N];
int p, q, e;

void init(void)	{
	memset (head, -1, sizeof (head));
	e = 0;
}

void add_edge(int u, int v, double w)	{
    edge[e] = Edge (v, w, head[u]);
    head[u] = e++;
}

double sqr(int x, int y)	{
	return (double) (x * x + y * y);
}
double cal_dis(int i, int j)	{
	return sqrt (sqr (x[i] - x[j], y[i] - y[j]));
}

double Prim(int s)	{
	memset (vis, false, sizeof (vis));
	for (int i=0; i<55; ++i)	d[i] = INF;
	priority_queue<Edge> Q;
	double ret = 0;
    for (int i=head[s]; ~i; i=edge[i].nex)	{
		int v = edge[i].v;	double w = edge[i].w;
		if (d[v] > w)	{
			d[v] = w;
            if (v == q) {
                ret += d[v];
                d[v] = 0;
            }
            Q.push (Edge (v, d[v], 0));
		}
	}
	vis[s] = true;  d[s] = 0;
	while (!Q.empty ())	{
		int u = Q.top ().v;	Q.pop ();
		if (vis[u])	continue;
		vis[u] = true;	ret += d[u];
		for (int i=head[u]; ~i; i=edge[i].nex)	{
			int v = edge[i].v;	double w = edge[i].w;
			if (v == q)	continue;
			if (!vis[v] && d[v] > w)	{
				d[v] = w;	Q.push (Edge (v, d[v], 0));
			}
		}
	}
	return ret;
}

int main(void)	{
	int n;
	while (scanf ("%d", &n) == 1)	{
		if (!n)	break;
		scanf ("%d%d", &p, &q);
		if (p > q)  swap (p, q);
        for (int i=1; i<=n; ++i)	{
            scanf ("%d%d", &x[i], &y[i]);
		}
		init ();
		for (int i=1; i<=n; ++i)	{
			for (int j=i+1; j<=n; ++j)	{
				add_edge (i, j, cal_dis (i, j));
				add_edge (j, i, cal_dis (i, j));
			}
		}
		printf ("%.2f\n", Prim (p));
	}

	return 0;
}

  

时间: 2024-10-04 01:08:23

Regionals 2012 :: HangZhou的相关文章

[Regionals 2012 :: Asia - Tokyo ]

链接: https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=566 A  uva live 6182 - Ginkgo Numbers 题目意思: 规则: 1.<m, n> · <x, y> = <mx ? ny, my + nx> 2.如果<m,n>是<p,q>的"除数",则存在<x,

Regionals 2012 :: Chengdu

题目连接 排行榜 A和I都是签到题 按位BFS K Yet Another Multiple Problem 题意:给一些可以用的数字,求最小的数,它由特定的数字组成且是n的倍数 分析:暴力枚举不可行,因为数字可能非常大.考虑到大数取模为0,BFS每一层即数位,递归输出路径. #include <bits/stdc++.h> const int N = 1e4 + 5; bool no[10]; std::pair<int, int> pre[N]; int dir[10]; bo

九度oj 1437 To Fill or Not to Fill 2012年浙江大学计算机及软件工程研究生机试真题

题目1437:To Fill or Not to Fill 时间限制:1 秒 内存限制:128 兆 特殊判题:否 提交:1488 解决:345 题目描述: With highways available, driving a car from Hangzhou to any other city is easy. But since the tank capacity of a car is limited, we have to find gas stations on the way fro

解决 U盘安装Windows Server 2012 R2 报错

报错原因: 使用UltraISO刻录镜像时会更改U盘的文件格式为FAT32, 而Server 2012 R2的安装文件install.wim为5G多,故安装失败. 解决方法: 1.按照正常的方法刻录镜像到U盘: 2.更改U盘文件系统: 进入命令行模式,输入 convert f: /fs:NTFS (F盘为我的U盘所在盘符) 3.把install.wim重新拷贝到U盘对应目录

Windows Server 2012配置L2TP服务环境

在上一篇文章<Windows Server 2012配置VPN服务环境>中讲解了在Windows Server2012环境中的基础VPN搭建,但是只能支持PPTP的VPN连接.这篇文章进一步完善了VPN基于L2TP的连接讲解. 在百度上也没有找到一个Windows2012 很全的L2TP服务搭建的方案,所以自己编辑了一个给有需要的朋友们参考. 准备环境:Windows Server 2012R2 数据中心版64位,基础的VPN服务环境已经搭建完成. 功能需求:完善VPN服务器来支持L2TP类型

VmWare平台Windows Server 2012 无响应宕机

我们生产服务器都部署在VMware ESXi 5.5平台上,最近大半年的时间,偶尔就会出现操作系统为Windows Servre 2012的服务器出现没有任何响应(unresponsive)的情况,出现问题的时候,服务器有下面一些现象: 1: 应用程序无法访问SQL Server数据库,使用Microsoft SQL Server Management Sutdio去测试连接数据库,也会返回连接错误. 2: 网络有时候能Ping通,有时候是Ping不通的情况. 3: 远程连接无法访问服务器,从V

SQL Server 2012 案例教程(贾祥素)——学习笔记

第2章 SQL Server 2012概述 1.SQL(Structed Query Language),结构化查询语言. 2.SSMS(SQL Server Mangement Studio),SQL Server 2012的操作环境. 3.连接SQL Server之前应先启动SQL Server服务,即SQL Server(MSSQLSERVER): 方法1 开始--所有程序--Microsoft SQL Server 2012--配置工具--SQL Server配置管理器. 方法2 控制面

SqlServer 2012 FileTable 文件表

SQL Server 2012 提供一种特殊的"文件表",也称为"FileTable". FileTable 是一种专用的用户表,它包含存储 FILESTREAM 数据的预定义架构以及文件和目录层次结构信息.文件属性.FileTable 功能为 SQL Server 中存储的文件数据提供对 Windows 文件命名空间的支持以及与 Windows 应用程序的兼容性支持.即可以在 SQL Server 中将文件和文档存储在称作 FileTable 的特别的表中,但是从

atitit.Windows Server 2003 2008 2012系统的新特性 attilax 总结

atitit.Windows Server 2003  2008  2012系统的新特性 attilax 总结 1. Windows Server 2008 新特性也可以归纳为4个方面. 1 2. 相比Windows Server 08,R2 2 3. win 2012  新特性 2 4. 参考 6 1. Windows Server 2008 新特性也可以归纳为4个方面. 即将发布的Windows Server 2008是企业级的应用平台,可以为CRM等企业级应用提供更好更强的支撑,其新特性也