博文

Zoj 2546 Walk Though the Forest(2008-03-02 15:36:00)

摘要: 2767343 2008-03-02 15:15:48 Accepted 2546 C++ 00:00.45 4364K C.D.=.= 写了个最简单的单源路径算法。完全是O(V^2)。比起2281的最小堆+链表差了不止一个档次…… 后续还有一个记忆化搜索的处理,当value[u]>value[v]的时候可以把u的路径可能数加到v上。Waterloo的那一次LC还比较简单,加上网站提供标程与数据,已经轻松Clear。  1#include <cstdio>
 2#include <string>
 3
 4#define MAXN 200000000
 5
 6int N, M, value[1001], visited[1001], a[1001][1001], num[1001];
 7
 8int init ();
 9void dijk ();
10void dp ();
11int func ( int );
12
13int main ()
14{
15    //freopen ( "in.txt", "r", stdin );
16    while ( init () )
17    {
18        dijk ();
19        dp ();
20  &......

阅读全文(2846) | 评论:1

Zoj 2740 Message System(2008-02-17 16:50:00)

摘要: 2753473 2008-02-17 16:25:45 Accepted 2740 C++ 00:00.00 436K C.D. 世界上最郁闷的事情,不是连续五个WA,而是连续莫名其妙的WA,却不知道错在哪里;比这更郁闷的事情,是改动之后的连续五个AC,却发现再也找不到刚才究竟错在哪里…… 遥想当年,浙大初赛时,雄姿英发;谈笑间,代码灰飞烟灭。故题重做,多情应笑我,迟来三年。卡了近三年的题目,回过头来再看也是一道简单题。 求图是否为连通生成树。预处理边数M,然后用并查集检查一下是否有回路,马上就可以解决。 因为满足生成树的情况下,M恒等于点数N-1,所以在预处理后就不需要考虑是否所有点都能够被访问。开始的时候写了一个BFS算法,遍历,结果失败。(我果然还是比较菜……= =) #include <cstdio>
#include <string>

int N, M, p[1001], num[1001];

int init ();
void init_set ();
int find_set ( int );
int union_set ( int, int );

int main ()
{
    //freopen ( "in.txt", "r", stdin );
    while ( init () )
    {
    }
    return 0;
}

void init_set ()
{
    in......

阅读全文(2769) | 评论:0

Zoj 2281 Way to Freedom(2008-02-11 15:23:00)

摘要:无向图中给定单源,求到某点路径中最小权边的最大值。

可以将其看成求单源最短路径的变种,使用dijkstra算法+最大堆。

单源最短路径的算法是:记录从源点出发访问每一点i的最短路为value[i],对于当前所有value中的最小值点u,进行BFS式的操作,对于每条Edge(u,v),如果edge(u,v)+value[u] < value[v] 则更新v。这是一个贪心的算法,可以证明每次出队列的u最优。
本题求的是最大单边,对此稍做修改。记录每条边目前能承受的最大重量为value[i](即从源点所遍历路径的最小权中的最大值)。设u是当前结点,对于每条Edge(u,v),当路径扩展到v时的最小value(min(edge, value[u]))——即路径的最短边——大于value[v] 时更新。在联通图内,每一次要求的路径都是最大,因此在BFS的过程中,边是从大到小排列,对于当前所有value中的最大值点u进行操作。因为点的数目巨大,遍历需要N<100000,可以用堆存放value。实际程序里堆存放的是点的index,使用一个辅助数组来存放index在heap中的位置,如heap[1] = 6, idx[6] = 1。为了编程方便,heap以1开始。

由于边数目巨大(M<1000000),因此使用链表储存。使用num数组保存起点为i的起始位置,next数组保存链表。num[i]=a,next[a]=b,next[b]=c,next[c]=d,next[d]=0,这里abcd都为边数组中的位置,表示以i为起点的边终点为abcd。
    1#include <cstdio>
  2#include <string>
  3
  4#define min(x, y) ( x < y ? x : y )
  5#define INF 2000000001
  ......

阅读全文(3423) | 评论:0

Zju 1586 QS Network(2007-03-27 14:53:00)

摘要:这题显然还是用prim,经过优化后的prim效率可以达到O(n2)。 离省赛越来越近,我也越来越没有状态,这种小白题从昨天晚上开始做,做到断网;今天爬起来继续做,才发现是把a[i][k]赋值 无限大的条件写错了——无良的出题者居然加入了两个端点间距离可能为0的情况...... #include <cstdio>
#include <string> int a[1010][1010], s[1010], dis[1010], t, n; void pd ()
{
    int i;
    for ( i = 0; i < n; i ++ )
    {
        printf ( "%d ", dis[i] );
    }
    printf ( "\n" );
} void init ()
{
    int i, k;
    scanf ( "%d", &n );
    for ( i = 0; i < n; i ++ )
    {
        scanf ( "%d", &s[i] );
    }
    for ( i = 0; i < n; i ++ )
    {
        for ( k = 0; k < n; k ++ )
        {
    &nb......

阅读全文(3783) | 评论:0

Zju 1705 Exchange Rates(2007-02-14 20:30:00)

摘要:放到图论里面,是因为用到了近似Floyd的算法。这题的输入麻烦,到最后直接用C++搞定了。 题目给出一系列物品之间的交换关系(比如6个i交换15个k),要求递推计算出给出的物品之间交换关系。采用的方法是建立图。a[i][k]代表了i和k交换时需要i的个数,a[k][i]是需要k的个数。每次更新信息之后对图遍历,对于那些已知a[i][j]和a[j][k]的路径,求出a[i][k],就如同Floyd求最短路径一样。 其实不用vector和string也可以解决,但是懒惰了 = = 。 PS:到了寒假,ZOJ似乎又复苏了,做题目的人好多。当初信心满满地想着要在3月份前做到400题,现在看起来像个笑话。好吧……随便做点,我最大的计划就是没有计划。 #include <iostream>
#include <vector>
#include <string>
#include <cstring>
using namespace std; int a[60][60];
vector < string > sv; void ps ()
{
 int i, k;
 for ( i = 0; i < sv.size (); i ++ )
 {
  for ( k = 0; k < sv.size (); k ++ )
  {
   printf ( "%d ", a[i][k] );
  }
 }
} int gcd ( int x, int y )
{
 int t;
 if ( x > y )
 {
  t = x, x = y, y = t;
 }
 while ( x )
 {
  t = x;
  x = y % x;
  y = t;
 }

阅读全文(3701) | 评论:0

Zju 1119 SPF(2006-09-11 23:24:00)

摘要: 2062175 2006-09-11 23:10:31 Accepted 1119 C++ 00:00.08 4368K St.Crux     若干年以前,这个题就应该被AC了——对弱题的冲动、严蔚敏老师的数据结构、标程——AC的三大要素我都有了,但是我一直停留在第一阶段——被邓公称作是一百年不变的初级阶段。三十年前,光明日报的编辑写过,实践是检验真理的唯一标准。然而在特定的时间,特定的地点,特定的人物身上,实践只会成为怀疑真理的唯一标准。幸好我还有第三样法宝。     修改过的标程 #include <cstdio>
#include <string> int x, y, vx, idx, a[1001][1001], dfn[1001], low[1001], sub[1001], root, c = 0, mx, mn;
// low[] means the lowest point one root and its subtree point to int min(int a, int b)
{
 return a > b ? b : a;
} void init()
{
 memset(dfn, 0, sizeof(dfn));
 memset(low, 0, sizeof(low));
 memset(sub, 0, sizeof(sub));
 idx = 1, low[vx] = dfn[vx] = idx, root = 0;
} void dfs(int i)
{
 int k; 
 for(k = mn; k <= mx; k ++)
 {
  if(a[i][k])  // k adjacent to i
  {
   if(!dfn[k]) // k not visited -- k is in subtre......

阅读全文(4391) | 评论:5

Zju 1789 The Suspects(2006-08-27 22:53:00)

摘要: 2045607 2006-08-27 22:32:59 Accepted 1789 C++ 00:00.02 668K St.Crux 2045606 2006-08-27 22:32:16 Accepted 1789 C++ 00:00.02 556K St.Crux 上面那个是优化过的,没看错.......可能数据碰巧不喜欢这样被优化。 这是标准解法。 #include <cstdio>
#include <string> int p[30001], r[30001], n, m, t, x, y, ans; int findset(int i)
{
 if(i == -1 || i >= n)
  return -1;
 if(p[i] != -1 && p[i] != i)
  p[i] = findset(p[i]);
 return p[i];
} int ufs(int a, int b)
{
 a = findset(a);
 b = findset(b);
 if(a == b) return a;
 if(a == -1) return b;
 if(b == -1) return a;
 if(r[a] < r[b])
 {
  p[a] = b;
  return b;
 }
 else
 {
  if(r[a] == r[b]) r[a] ++;
  p[b] = a;
  return a;
 }
} void init()
{
 memset(r, 0, sizeof(r));
 int i;
 for(i = 0; i < n......

阅读全文(3826) | 评论:1

Zju 1103 Hike on a Graph(2006-08-16 19:28:00)

摘要: 2025283 2006-08-16 19:12:19 Accepted 1103 C++ 00:00.07 1544K St.Crux 这个题其实不难。可是我用了半个下午的时间研究如何dp......这件事告诉我一个深刻的道理......下次用一个小时研究就可以了。 好吧,这个题还是有写头滴,幸好queue让我简便了不少。还有一开始看错题意,每一枚棋子是不能同时移动的。 #include <iostream>
#include <fstream>
#include <queue>
#include <cstring>
using namespace std; class pt
{
public:
 int i, k, j, c;
}; queue<pt> pq, tq, ttq;
int n, p1, p2, p3, b[50][50][50], ans;
char a[50][50];
void init()
{
 p1 --, p2 --, p3 --;
 memset(b, 0, sizeof(b));
 ans = -1;
 pq = tq;
 b[p1][p2][p3] = 1;
 pt tpt;
 tpt.i = p1, tpt.k = p2, tpt.j = p3, tpt.c = 0;
 pq.push(tpt);
} void bfs()
{
 while(!pq.empty())
 {
  //pb();
  pt tpt, ttpt;
  int i, k, j;
  tpt = pq.front();
  if(tpt.i == tpt.k && tpt.k == tpt.j)
  {
  &nb......

阅读全文(3813) | 评论:0

Zju 1092 Arbitrage(2006-08-14 23:33:00)

摘要: 2021578 2006-08-14 23:10:47 Accepted 1092 C++ 00:00.37 856K St.Crux 输出的时候犯了一个小错误:"Yes"当作“YES”了。 这个题是很基础的最短路径题,不限次数倒买倒卖,求能否过一定的收益率(这里为1)。我记得uva上有一个题是问在t次交换内能否达到一定的汇率......那样似乎还要记录路径了......上次学校里搞选拔赛的时候做过,做不出。现在还是做不出 TAT 另,memset(a, 0, sizeof(a))对double数组无效。但可以写memset(a, 0x00, sizeof(a)) #include <iostream>
#include <fstream>
#include <cstring>
#include <string>
#include <map>
using namespace std; double a[30][30];
map<string, int> sm, dm;
int n, c = 0, ac; int main()
{
 //ifstream cin("in.txt");
 while(cin >> n && n)
 {
  sm = dm;  
  int i, k, t, j;
  for(i = 0; i < n; i ++)
  {
   string s;
   cin >> s;
   sm[s] = i;
   for(k = 0; k < n; k ++)
   {
    a[i][k] = 0;  //清零
 &n......

阅读全文(3923) | 评论:0

Zju 1082 Stockbroker Grapevine(2006-08-12 20:45:00)

摘要: 2017811 2006-08-12 20:23:54 Accepted 1082 C++ 00:00.00 428K St.Crux 最短路径的前提就是i点到k点能够访问。反之就是访问不能。 W.Floyd把j放在外面,i,k放在循环里面。我曾经错误的认为i和k是应该在外层循环,结果造成了长期的心理错觉,以致于一遇见这样的题目就ac不能,进而对Floyd先生产生了强烈的怨念。但是Floyd有证明么? #include <cstdio>
#include <string> #define MX 1001 int a[100][100], n, m; int main()
{
 //freopen("in.txt", "r", stdin);
 while(scanf("%d", &n) && n)
 {
  int i, k, j, ac = 1;
  for(i = 0; i < n; i ++)
  {
   scanf("%d", &m);
   for(k = 0; k < n; k ++)
   {
    a[i][k] = MX;
   }
   for(k = 0; k < m; k ++)
   {
    int ti, tn;
    scanf("%d %d", &ti, &tn);
    a[i][ti - 1] = tn;
   }
  }
  //pa();
  f......

阅读全文(4196) | 评论:0