ACM 题目求最优解 我TLE了求助啊.

gqjjqg 2009-10-19 08:20:13
加精
描述:
在二维坐标上给你M个点(M是偶数)的坐标,坐标都是整数,你可以任意联接其中两点(不管中间有没有障碍),这两点就消失了(和游戏里的一样).但消去两点的路径和两个点的位置有关,也就是说路径的长度等于两点X轴与Y轴差的绝对值之和.比如一个点坐标为(10,10),另外一个点坐标为(2,3),那么消去这两个点的路径长度为8+7=15.问消去所有点的路径长度之和最小值是多少?

第一行输一个正整数N,下面有N种连连看的地图

每种地图的第一行输入一个正整数M
(M是偶数,并且2=< M <=20),代表地图上有M个点.
下面有M行,每一行都有两个整数,代表这个点的X轴坐标与Y轴坐标.
(坐标的绝对值不会大于十万)

输出共N行,每行都是消去所有点的路径长度之和的最小值.

Sample Input
3

2
10 10
2 3

2
0 1
0 2

4
0 2
0 3
0 5
0 6

Sample Output
15
1
2

-------------------------
我的方法 :

#include <stdio.h>
struct Point
{
int x, y;
}PointList[21];
int g_nSatusList[1024][1024];
int g_nPointList[21][21];
int g_nFlagList[21] = {0};
int n = 0;
int valuex = 1023, valuey = 1023;
int max1 = 0, max2 = 0;
int abs(int argA, int argB)
{
return argA > argB ? argA - argB : argB - argA;
}
int DeepInto(int Limit)
{
int i = 0 ,j = 0;
if (Limit == 2)
{
int x = -1, y = -1;
for (i = 0; i < n; i++)
{
if (g_nFlagList[i] == 0)
{
if (x == -1)
x = i;
else
y = i;
}
}
return g_nPointList[x][y] == 0 ? g_nPointList[y][x] : g_nPointList[x][y];
}
int minitemp = 200000000;
int tpj = -1;
for (i = 0; i < n; i++)
{
if (g_nFlagList[i] == 0)
{
if (tpj == -1)
tpj = i; //记录开始点
g_nFlagList[i] = 1;

if (i < 10)
valuex = (valuex ^ (1 << i));
else
valuey = (valuey ^ (1 << (i - 10)));

int j = 0;
for (j = tpj; j < n; j++)
{
if (g_nFlagList[j] == 0 && minitemp > g_nPointList[i][j])
{
g_nFlagList[j] = 1;

if (j < 10)
valuex = (valuex ^ (1 << j));
else
valuey = (valuey ^ (1 << (j - 10)));

int temp;

if (g_nSatusList[valuex][valuey] != -1)
{
temp = g_nSatusList[valuex][valuey];
}
else
{
temp = DeepInto(Limit - 2);
}
int ijLength = g_nPointList[i][j] == 0 ? g_nPointList[j][i] : g_nPointList[i][j];
if (minitemp > ijLength + temp)
{
minitemp = ijLength + temp;
}

if (g_nSatusList[valuex][valuey] == -1 ||
g_nSatusList[valuex][valuey] > minitemp)
g_nSatusList[valuex][valuey] = minitemp;
g_nFlagList[j] = 0;

if (j < 10)
valuex = (valuex ^ (1 << j));
else
valuey = (valuey ^ (1 << (j - 10)));
}
}
g_nFlagList[i] = 0;
if (i < 10)
valuex = (valuex ^ (1 << i));
else
valuey = (valuey ^ (1 << (i - 10)));
}
}
return minitemp;
}
void initailArray(int MX, int MY)
{
int i = 0, j = 0;
for (;i < MX; i++)
for(j = 0; j < MY; j++)
g_nSatusList[i][j] = -1;
}
int main ()
{
int CaseN = 0;
while (1 == scanf("%d", &CaseN))
{
while (CaseN--)
{
scanf("%d", &n);
int i = n;
max1 = 0, max2 = 0;
while (i--)
{
scanf("%d %d", &PointList[i].x, &PointList[i].y);
if (i < 10)
max1 = max1 | (1 << i);
else
max2 = max2 | (1 << (i - 10));
}
i = n;
while (i--)
{
int j = 0;
while (j < i)
{
g_nPointList[i][j] = abs(PointList[i].x, PointList[j].x) +
abs(PointList[i].y, PointList[j].y);
j++;
}
}
i = n;
initailArray(max1 + 1, max2 + 1);
valuex = max1, valuey = max2;
printf("%d\n", DeepInto(i));
}
}
return 0;
}


20 个点的数据的时候 要大概3S左右:
例如这组
20
1 2
1000 1
1000 2
3 5
8 11111
222 156
123 123
125 159
11111 12
2101 23
15687 1264
456 4561
121 2315
1 123
1 3
2 56
6 98
9000 12
6000 112
2 1111
求高手解答..代码基本无注释,不好意思..
我的思路:穷举搜索的话 次数超多死T,T的原因应该是 很多组数据时重复在做的,所以,我用一个 二维数组保存做过的 组合,减少重复量,不过我能做的也就这么多....还是不行,20个点搜索 还是要 3S 多...

...全文
1965 147 打赏 收藏 转发到动态 举报
写回复
用AI写文章
147 条回复
切换为时间正序
请发表友善的回复…
发表回复
jdtxse 2010-05-16
  • 打赏
  • 举报
回复
学习了
绿色夹克衫 2009-11-14
  • 打赏
  • 举报
回复
是吗!周末我去AC一下试试,忙了好一段时间了,ACM很久没碰了!

[Quote=引用 144 楼 gqjjqg 的回复:]
补充一下: 您给我的参考代码貌似有点问题..
[/Quote]
gqjjqg 2009-11-14
  • 打赏
  • 举报
回复
[Quote=引用 145 楼 litaoye 的回复:]
是吗!周末我去AC一下试试,忙了好一段时间了,ACM很久没碰了!

引用 144 楼 gqjjqg 的回复:
补充一下: 您给我的参考代码貌似有点问题..

[/Quote]

这个不会是您随手写的吧?
思路是不是这样子的?:第一个循环我不知道为什么这么做....之后是随机化一个数列,从0 - 1<<n 然后 下面的代码就有点难懂了,看起来做的就是 边找两个点 边算出mat 权。
很巧妙,但是代码有点难以琢磨。

------
那个不是您AC的? 晕.....
要是能解释下做法就好了..
gqjjqg 2009-11-13
  • 打赏
  • 举报
回复
不好意思分数不多...
只好给相对比较有贡献的人....
谢谢其他关注的朋友....
gqjjqg 2009-11-13
  • 打赏
  • 举报
回复
补充一下: 您给我的参考代码貌似有点问题..
gqjjqg 2009-11-13
  • 打赏
  • 举报
回复
[Quote=引用 142 楼 litaoye 的回复:]
比较感兴趣的是LZ AC了么?
[/Quote]
被你的兴趣打败了...
一定要AC么?

这个对于我这种程度的人来说独立的写还是有难度的,比如你提供的随机化方法,还有那个DP的代码我都还在观摩中...
毕竟我不是研究算法方面的,只是因为这个是我第一次接触ACM的时候遇到的比较感兴趣的问题而已..而且我还要上班....
流汗......
绿色夹克衫 2009-11-13
  • 打赏
  • 举报
回复
比较感兴趣的是LZ AC了么?
laiguo 2009-11-12
  • 打赏
  • 举报
回复
貌似我学的数据结构和大家的不一样?为什么有的算法没听过?
gqjjqg 2009-11-10
  • 打赏
  • 举报
回复
[Quote=引用 138 楼 torey 的回复:]
我的不行
[/Quote]

汗.....
Torey 2009-11-09
  • 打赏
  • 举报
回复
我的不行
Torey 2009-11-09
  • 打赏
  • 举报
回复
Private Sub Command1_Click()
Dim iFF As Integer
Dim x As Long
Dim y As Long
Dim xy As Collection
Dim xys As Collection
Dim Spaces As Collection
Dim Space As Collection
Dim SpacesPath As Collection
Dim SpaceLong As Long
Dim I, L, M As Integer
Dim time1 As String
Dim time2 As String
time1 = Time
iFF = FreeFile
Open App.Path & "\xy.txt" For Input As iFF
Set xys = New Collection
Do Until EOF(iFF)
Line Input #iFF, sLine
If InStr(1, sLine, ",") Then
x = Trim(Left(sLine, InStr(1, sLine, ",") - 1))
y = Trim(Right(sLine, Len(sLine) - InStr(1, sLine, ",")))
Set xy = New Collection
xy.Add x
xy.Add y
xys.Add xy
End If
Loop
Close #iFF
Set SpacesPath = New Collection

Call CountShort1(xys, "", 0, SpacesPath)
time2 = Time
End Sub

Sub CountShort1(ByVal xys As Collection, ByVal Paths As String, ByVal PathLong As Long, SpacesPath As Collection)
Dim xys1() As Collection
Dim xy1 As Collection
Dim SpaceLong1 As Long
Dim x1 As Long
Dim y1 As Long
Dim x2 As Long
Dim y2 As Long
Dim I, L, M, N As Integer
Dim Paths1 As String
Dim PathLong1 As Long
On Error GoTo Errs
PathLong1 = PathLong
Paths1 = Paths
If xys.Count = 2 Then
SpaceLong1 = 0
If xys.Item(1).Item(1) >= xys.Item(2).Item(1) Then
SpaceLong1 = xys.Item(1).Item(1) - xys.Item(2).Item(1)
Else
SpaceLong1 = xys.Item(2).Item(1) - xys.Item(1).Item(1)
End If
If xys.Item(1).Item(2) >= xys.Item(2).Item(2) Then
SpaceLong1 = SpaceLong1 + xys.Item(1).Item(2) - xys.Item(2).Item(2)
Else
SpaceLong1 = SpaceLong1 + xys.Item(2).Item(2) - xys.Item(1).Item(2)
End If
PathLong1 = PathLong1 + SpaceLong1
Paths1 = Paths1 & xys.Item(1).Item(1) & "," & _
xys.Item(1).Item(2) & "," & _
xys.Item(2).Item(1) & "," & _
xys.Item(2).Item(2) & "|"
If SpacesPath.Count = 0 Then
SpacesPath.Add PathLong1
SpacesPath.Add Paths1
Else
If PathLong1 < SpacesPath.Item(1) Then
SpacesPath.Remove 1
SpacesPath.Remove 1
SpacesPath.Add PathLong1
SpacesPath.Add Paths1
End If
End If
Exit Sub
Else
If xys.Count = 0 Then
If SpacesPath.Count = 0 Then
SpacesPath.Add PathLong1
SpacesPath.Add Paths1
Else
If PathLong1 < SpacesPath.Item(1) Then
SpacesPath.Remove 1
SpacesPath.Remove 1
SpacesPath.Add PathLong1
SpacesPath.Add Paths1
End If
End If
Exit Sub
End If
End If
M = xys.Count
ReDim xys1(M) As Collection
For M = 1 To xys.Count
Set xys1(M) = New Collection
Next
For M = 1 To xys.Count
For I = 1 To xys.Count
Set xy1 = New Collection
x1 = xys.Item(I).Item(1)
y1 = xys.Item(I).Item(2)
xy1.Add x1
xy1.Add y1
xys1(M).Add xy1
Next
Next
M = xys.Count
For I = 2 To M
SpaceLong1 = 0
If xys.Item(1).Item(1) >= xys.Item(I).Item(1) Then
SpaceLong1 = xys.Item(1).Item(1) - xys.Item(I).Item(1)
Else
SpaceLong1 = xys.Item(I).Item(1) - xys.Item(1).Item(1)
End If
If xys.Item(1).Item(2) >= xys.Item(I).Item(2) Then
SpaceLong1 = SpaceLong1 + xys.Item(1).Item(2) - xys.Item(I).Item(2)
Else
SpaceLong1 = SpaceLong1 + xys.Item(I).Item(2) - xys.Item(1).Item(2)
End If
Pathslong1 = Pathslong1 + SpaceLong1
If SpacesPath.Count = 0 Then
Paths1 = Paths1 & xys.Item(1).Item(1) & "," & _
xys.Item(1).Item(2) & "," & _
xys.Item(I).Item(1) & "," & _
xys.Item(I).Item(2) & "|"
xys1(I).Remove I
xys1(I).Remove 1
Call CountShort1(xys1(I), Paths1, Pathslong1, SpacesPath)
Else
If Pathslong1 < SpacesPath.Item(1) Then
Paths1 = Paths1 & xys.Item(1).Item(1) & "," & _
xys.Item(1).Item(2) & "," & _
xys.Item(I).Item(1) & "," & _
xys.Item(I).Item(2) & "|"
xys1(I).Remove I
xys1(I).Remove 1
Call CountShort1(xys1(I), Paths1, Pathslong1, SpacesPath)
End If
End If
Next
Exit Sub
Errs:
MsgBox Err.Description
End Sub

绿色夹克衫 2009-11-09
  • 打赏
  • 举报
回复
hh_xj同志解释的很好,比我自己说的还清楚,恩,就是这个意思。证明的话,应该是可以的,
其实画画图就清楚了,之前只动脑子不动手,就是差点儿。
whywen_MoJian 2009-11-09
  • 打赏
  • 举报
回复
mark
gqjjqg 2009-11-08
  • 打赏
  • 举报
回复
这个世界不缺少做的人,最缺少想的人...
130楼大爱...
hh_xj 谢谢你的解释..
hh_xj 2009-11-08
  • 打赏
  • 举报
回复
[Quote=引用 130 楼 litaoye 的回复:]
本来想用类似RTree + DP来试试,后来画了画图,发现应该可以有N^2的解法

如图所示,Sum(PA1) = R1 + R2 + R3 + R4 + Sum(PA2)

Sum(PA2) = Min(R5+Sum(PA3),R6*2 + Sum(PA4))

有了这个状态转移,用DP就可以解了!


[/Quote]
对照着图理解了一遍,litaoye兄的的算法思想是:
1,从四周找出出头的点,将它与内部的点的垂直距离先提取出,这4个距离是肯定会出现在最终的最小和里的。
2,将点按照距离相应的平移进去。此时点并未消除。
3,然后判断外围的点否可以消除。可以消除则提取两个平行的距离,且点消除;否则提取两个垂直距离,且点继续移进。

直觉上这个算法运行过程会把各点不断压扁,可能最后所有点会都在一直线上。
很有创意,正确性,我证明不了,也反驳不了,继续关注
绿色夹克衫 2009-11-08
  • 打赏
  • 举报
回复
是不太一样,因为对XY轴最靠边缘的点做了平移,这也是可以用DP解的基础!

[Quote=引用 131 楼 gqjjqg 的回复:]
引用 130 楼 litaoye 的回复:
本来想用类似RTree + DP来试试,后来画了画图,发现应该可以有N^2的解法

如图所示,Sum(PA1) = R1 + R2 + R3 + R4 + Sum(PA2)

Sum(PA2) = Min(R5+Sum(PA3),R6*2 + Sum(PA4))

有了这个状态转移,用DP就可以解了!




图看起来不太一样...
[/Quote]
gqjjqg 2009-11-08
  • 打赏
  • 举报
回复
[Quote=引用 130 楼 litaoye 的回复:]
本来想用类似RTree + DP来试试,后来画了画图,发现应该可以有N^2的解法

如图所示,Sum(PA1) = R1 + R2 + R3 + R4 + Sum(PA2)

Sum(PA2) = Min(R5+Sum(PA3),R6*2 + Sum(PA4))

有了这个状态转移,用DP就可以解了!


[/Quote]

图看起来不太一样...
绿色夹克衫 2009-11-07
  • 打赏
  • 举报
回复
本来想用类似RTree + DP来试试,后来画了画图,发现应该可以有N^2的解法

如图所示,Sum(PA1) = R1 + R2 + R3 + R4 + Sum(PA2)

Sum(PA2) = Min(R5+Sum(PA3),R6*2 + Sum(PA4))

有了这个状态转移,用DP就可以解了!

with_daniel 2009-11-07
  • 打赏
  • 举报
回复
不懂啊!
zgmsh007 2009-11-05
  • 打赏
  • 举报
回复
这个真的很好
加载更多回复(125)

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧