poj-1129

//372K 0MS G++
#include <stdio.h>
#include <assert.h>
#include <string.h>


#define BEGIN 'A'


int graph[26][26];


int repeaterUsingChannel[26];


int channelUsedInfo[27]; // channel 1 ~ 27


int totalChannelNum = 0;


void dfs(int begin, int totalNum) {
// printf("%d %d\n", begin, totalNum);
if (begin >= totalNum) { // all repeater processed
return;
}


if (!begin) { // first repeater
repeaterUsingChannel[0] = 1;
channelUsedInfo[1] = 1;
totalChannelNum += 1;
// printf("%d %d\n", begin, 1);
} else {
int adjacentProcessedRepeaterChannel[27] = {0};
for (int i = 0; i < begin; i++) {
// printf("%d %d %d %d\n", begin, i, graph[begin][i], repeaterUsingChannel[i]);
if (graph[begin][i] == 1) { //adjacent with repeater i 
adjacentProcessedRepeaterChannel[repeaterUsingChannel[i]] = 1;
}
}
int usableChannel = 0;
for (int i = 1; i <= 27; i++) { // find first usable channel
if (!adjacentProcessedRepeaterChannel[i]) {
usableChannel = i;
break;
}
}
assert(usableChannel);
repeaterUsingChannel[begin] = usableChannel;
if (channelUsedInfo[usableChannel]) // check if has been used by other no-adjacent repeater before
{


} else {
// printf("%d %d\n", begin, usableChannel);
totalChannelNum++;
channelUsedInfo[usableChannel] = 1;
}


}
dfs(begin + 1, totalNum); // process next repeator
}


void getMinChannelNum(int repeaterNum) {
// for (int i = 0; i < repeaterNum; i++) {
// for (int j = 0; j < repeaterNum; j++) {
// printf("%d ", graph[i][j]);
// }
// printf("\n");
// }


dfs(0, repeaterNum);
if (totalChannelNum == 1) {
printf("1 channel needed.\n");
} else {
printf("%d channels needed.\n", totalChannelNum);
}
}


int main() {
int repeaterNum = 0;
while(1) {
scanf("%d", &repeaterNum);
if (!repeaterNum) {
return 0;
}
totalChannelNum = 0;
memset(graph, 0, sizeof(graph));
memset(repeaterUsingChannel, 0, sizeof(repeaterUsingChannel));
memset(channelUsedInfo, 0, sizeof(channelUsedInfo));
char repeaterInfo[30];
for (int i = 0; i < repeaterNum; i++) {
scanf("%s", repeaterInfo);
for (int j = 2; j < strlen(repeaterInfo); j++) {
graph[i][repeaterInfo[j] - BEGIN] = 1;
// repeaterInfo[i][repeaterInfo[j] - BEGIN] = 1;
}
}
getMinChannelNum(repeaterNum);
}

}


算是水题, 没有用到多技巧性的解法,就是经典的状态记录+步进式 搜索树.

不过这一类题一般阐述都是要求最优解,而按照搜索树来一般求出来的就是最优解(因为中间有channel资源重用)

阐述一下流程:

首先因为题目的输入是ABCD...,所以首先要做的就是转化成数字,-'A'即可.

然后就是从A开始遍历每个repeater了(我这里直接用的递归调用,dfs(1) -> dfs(2) -> .. -> dfs(last)),针对每个repeater的相邻repeater使用的channel情况来决定此repeater的channel。

注意的是,在处理第i个repeater时,考虑相邻的repeater时,只考虑之前已经分配过channle即已经处理过的repeater, 1~ i-1,

遍历一遍相邻的已经分配的repeater的channel,搞一个channelMap数组记录都有哪些channel被周边使用,

然后从1开始遍历此channelMap数组,找到的第一个没有周边占用的channel即为此repeater的channel(重用了channel资源,达到最优解)

同时因为题目最后要求输出总共的channel数量,因此还要搞一个全局的channel使用情况数组来记录某个channel是否已经被某个repeater使用了,

如果当前分配给此repeatr的channel之前没有被使用过,那么标记此数组的相应位置,并且使用的channelNum+1。

题目难点就在于每次迭代时,要记录和更新的信息多(这就是空间换时间的副作用),很容易有遗漏.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值