求解算法,如何求最优Euler回路?

idler 2001-09-23 04:19:10
已知含有N个顶点的图G肯定含有Euler回路。图G中的每个顶点都给顶了标号。
要求:最优Euler回路P,使得P上的所有顶点序号所组成的N进制数最小。
...全文
176 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
mathe 2001-09-29
  • 打赏
  • 举报
回复
我也在忙着工作呀
idler 2001-09-28
  • 打赏
  • 举报
回复
看中文多舒服!
to mathe:你能不能把你的算法用中文详细描述一遍?我最近正在考试,实在没有时间仔细研究。
mathe 2001-09-27
  • 打赏
  • 举报
回复
没有呀,我给出的算法是正确的呀。只要每一次我们都将那些只能通向终点的点做上标记,防止先选择它们就行了(我的算法里使用的数组NearEnd就是起这个作用的)。
idler 2001-09-26
  • 打赏
  • 举报
回复
好像问题太复杂了
mathe 2001-09-26
  • 打赏
  • 举报
回复
不对,
such as graph

1 2 3 4 5
1 0 1 1 0 0
2 1 0 1 1 1
3 1 1 0 1 1
4 0 1 1 0 0
5 0 1 1 0 0

We should first take 1, then take 2 and remove edge {1,2}
Then take 3 and remove edge {2,3},but now we cannot take vertex 1.(We should take vertex 4 now).
That's why in my algorithm, I add an array NearEnd to indicate a path that will result in the End vertex.
By the way, in my algorithm, I have not consider the situation that there's a vertex with odd degree, because when you say "Hui Lu", I think it means it the path should come back to the original vertex. In the fact, the algorithm is same if consider those graphs with two odd degree.
starfish 2001-09-26
  • 打赏
  • 举报
回复
看来果然是近似算法,我也觉得这个问题很像是NP的,这就有点像货郎担问题,只不过权函数不同罢了。
idler 2001-09-25
  • 打赏
  • 举报
回复
我也没办法证明。
但看上去好像是对的。因为最后的回路实际上和堆栈内的元素顺序有关。那么:堆栈正序-〉回路到序-〉倒序的倒序为正序。
管它呢!反正都PASS了。
有谁找到反例请告诉我。
starfish 2001-09-25
  • 打赏
  • 举报
回复
USACO的贪心法不一定正确吧,能证明他的正确性么?我觉得这只是一个近似解法
wilddragon 2001-09-25
  • 打赏
  • 举报
回复
up
idler 2001-09-25
  • 打赏
  • 举报
回复
其实只要每次寻找序号最小的点,然后再到序输出就可以了。下面是USACO上面的分析。
Assuming you pick the lowest index vertex connected to each node, the Eulerian Path algorithm actually determines the path requested, although in the reverse direction. You must start the path determination at the lowest legal vertex for this to work.

/* Prob #5: Riding the Fences */
#include <stdio.h>
#include <string.h>

#define MAXI 500
#define MAXF 1200
char conn[MAXI][MAXI];
int deg[MAXI];
int nconn;

int touched[MAXI];

int path[MAXF];
int plen;

/* Sanity check routine */
void fill(int loc)
{
int lv;

touched[loc] = 1;
for (lv = 0; lv < nconn; lv++)
if (conn[loc][lv] && !touched[lv])
fill(lv);
}

/* Sanity check routine */
int is_connected(int st)
{
int lv;
memset(touched, 0, sizeof(touched));
fill(st);
for (lv = 0; lv < nconn; lv++)
if (deg[lv] && !touched[lv])
return 0;
return 1;
}

/* this is exactly the Eulerian Path algorithm */
void find_path(int loc)
{
int lv;

for (lv = 0; lv < nconn; lv++)
if (conn[loc][lv])
{
/* delete edge */
conn[loc][lv]--;
conn[lv][loc]--;
deg[lv]--;
deg[loc]--;

/* find path from new location */
find_path(lv);
}

/* add this node to the `end' of the path */
path[plen++] = loc;
}

int main(int argc, char **argv)
{
FILE *fin, *fout;
int nfen;
int lv;
int x, y;

if (argc == 1)
{
if ((fin = fopen("fence.in", "r")) == NULL)
{
perror ("fopen fin");
exit(1);
}
if ((fout = fopen("fence.out", "w")) == NULL)
{
perror ("fopen fout");
exit(1);
}
} else {
if ((fin = fopen(argv[1], "r")) == NULL)
{
perror ("fopen fin filename");
exit(1);
}
fout = stdout;
}

fscanf (fin, "%d", &nfen);
for (lv = 0; lv < nfen; lv++)
{
fscanf (fin, "%d %d", &x, &y);
x--; y--;
conn[x][y]++;
conn[y][x]++;
deg[x]++;
deg[y]++;
if (x >= nconn) nconn = x+1;
if (y >= nconn) nconn = y+1;
}

/* find first node of odd degree */
for (lv = 0; lv < nconn; lv++)
if (deg[lv] % 2 == 1) break;
/* if no odd-degree node, find first node with non-zero degree */
if (lv >= nconn)
for (lv = 0; lv < nconn; lv++)
if (deg[lv]) break;
#ifdef CHECKSANE
if (!is_connected(lv)) /* input sanity check */
{
fprintf (stderr, "Not connected?!?\n");
return 0;
}
#endif

/* find the eulerian path */
find_path(lv);

/* the path is discovered in reverse order */
for (lv = plen-1; lv >= 0; lv--)
fprintf (fout, "%i\n", path[lv]+1);
return 0;
}
wilddragon 2001-09-24
  • 打赏
  • 举报
回复
关注
wilddragon 2001-09-24
  • 打赏
  • 举报
回复
哈哈
mathe 2001-09-24
  • 打赏
  • 举报
回复
for(i=1;i<=N;i++)NearEnd[i]=0;
curi=1;
do
{
Find smallest i that V[i] near V[curi] && NearEnd[i]==0.
If such i exist
{
Output(i);
Remove Edge(V[i],V[curi]);
if(curi==1&°ree(V[curi])==1||Degree(V[curi])==2)
{
if(curi==1||Exist V[k] near V[curi]&&NearEnd[k]==1)
{
NearEnd[curi]==1;
Find k that V[k] near V[i] and NearEnd[k]==0;//only one k.
while(Degree(V[k]==2)
{
nextk is the value that V[k] near V[nextk] && NearEnd[next]==0;//only one point
k=nextk;
}
}
}
else
{ //There must only those vertex with NearEnd[k]==1 left
while(Find i that V[i] near V[curi])
{
Output(i);
Remove Edge(V[i],V[curi]);
curi=i;
}
return;
}
}while(1);
idler 2001-09-24
  • 打赏
  • 举报
回复
to mathe: 怎么做?
wilddragon 2001-09-24
  • 打赏
  • 举报
回复
期待答案
mathe 2001-09-23
  • 打赏
  • 举报
回复
太简单了
idler 2001-09-23
  • 打赏
  • 举报
回复
补充一下:
标号从1到N,那么就应该是N+1进制。

33,007

社区成员

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

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